How to use instance of New Object in With... Block - vb.net

Dim objects As New List(Of Object)
With New Object
.prop1 = "Property 1"
.prop2 = "Property 2"
objects.add(.instance) 'i mean instance of New Object
End With
is it possible.
I ask new question because last question has mislead information and I don't give right answer. so here code.

No it is not possible. The With statement basically creates an implicit variable. All you can do with that variable is access members and there is no member that returns a reference to the object itself.
If you want succinct code to create, populate and add an object to a list then do this:
myList.Add(New SomeType With {.SomeProperty = someValue,
.SomeOtherProperty = someOtherValue})
Interestingly, you can make it work the way you wanted if you create your own extension method. I was under the impression that you could not extend the Object class but either I was wrong or that has changed because I just tried in VB 2013 and it worked. You can write a method like this:
Imports System.Runtime.CompilerServices
Public Module ObjectExtensions
<Extension>
Public Function Self(Of T)(source As T) As T
Return source
End Function
End Module
and then do something like this:
With New SomeType
.SomeProperty = someValue
.SomeOtherProperty = someOtherValue
myList.Add(.Self())
End With
I'm not sure that that really provides any benefit though, given the availability of the object initialiser syntax that I demonstrated first.
Hmmm... I just realised that that's not actually extending the Object class. It was my original intention to try to do so but then I realised that a generic method was better because it would then return the same type as you call it on. I did just test it with a non-generic method extending type Object and it did still worked though.

You should to create your own class By example :
Public Class Car
Private _NumberCar As Integer
Public Property NumberCar() As Integer
Get
Return _NumberCar
End Get
Set(ByVal value As Integer)
_NumberCar = value
End Set
End Property
Private _ColorCar As Color
Public Property ColorCar() As Color
Get
Return _ColorCar
End Get
Set(ByVal value As Color)
_ColorCar = value
End Set
End Property
Private _OwnerName As String
Public Property OwnerName() As String
Get
Return _OwnerName
End Get
Set(ByVal value As String)
_OwnerName = value
End Set
End Property
End Class
and in the Class where you want to add the cars object do this :
Dim CarList As New List(Of Car)
Dim item As New Car
With item
.NumberCar = 1243
.ColorCar = Color.Red
.OwnerName = "Ibra"
End With
CarList.Add(item)
strong text

Related

Class object property which references another object instance of same object type

I have a class object which looks like this:
Public Class item
Public Property ID
Public Property Name
Public Property Description
Public Property Type
Public Property Alias
End Class
I am currently storing these as a dictionary like this:
Public Class Items
Public ReadOnly dict Dictionary(Of String, item) From {
{"A", New item With {.Name = "Object A", .Description = "Object A description"}},
{"B", New item With {.Name = "Object B", .Description = "Object B description"}},
{"C", New item With {.Alias = "A"}}
}
Public Function GetItem(ByVal ID As String) As item
Return If(dict.ContainsKey(ID), idct.Item(ID), Nothing)
End Function
End Class
The complexity is that sometimes an item will not have any properties itself but instead has an .Alias property which says "All of my properties are the same as item with this ID, check that object instead".
How should I write my class object item so that this code returns "Object A":
Dim newItem As item = GetItem("C")
Debug.WriteLine(item.Name)
Object C is an alias of Object A so I should return some properties (not always all of them) for Object A instead of Nothing.
A way around this is by adding the below function to the Items class:
Public Function GetItemDescription(ByVal ID As String) As String
If dict.ContainsKey(ID) Then
If dict.Item(ID).Description = "" Then
Return GetItemDescription(dict.Item(ID).Alias)
Else
Return dict.Item(ID).Description
End If
Else
Return ""
End If
End Function
However this doesn't feel like the correct way as then I have to repeatedly call a set of Items.GetPropertyXYZ functions rather than directly referencing the object (e.g. item.Description would have to be GetItemDescription("C")
Is my solution acceptable from a design persepctive, or is there a better way to achieve this?
Try this:
Public Function GetItem(ByVal [alias] As String) As item
Return dict.Where(Function(a) a.Key = [alias]).Select(Function(b) b.Value).FirstOrDefault
End Function
Edit 1
Certainly it returns the "C" item because its wrong. Sorry.
This one works (Tested):
Public Function GetItem(ByVal ID As String) As item
Dim itm As item = dict.Where(Function(a) a.Key = ID).Select(Function(b) b.Value).FirstOrDefault
Return If(itm IsNot Nothing, If(itm.Alias IsNot Nothing, dict(itm.Alias), itm), Nothing)
End Function
JQSOFT's answer does achieve a similar thing, however I've since realised a more granular way I can achieve the same result.
Private Property _description As String
Public Property Description As String
Get
If _Description = "" Then
If [Alias] IsNot Nothing Then
Return dict.Item([Alias]).Description
Else
Return ""
End If
Else
Return _description
End If
End Get
Set(value As String)
_description = value
End Set
End Property
This way allows me to specify whether I return the data from Object A at property level, rather than returning an entirely different object.
Also, .Alias is a terrible property name as it's also a keyword, I'm going to use .Synonym.

Can't iterate through each property of a custom object

I have this class:
Public Class clsServCasam
Public ID As Long
Public CANT As Decimal
Public PRICE As Decimal
End Class
I create a variable of that type and get the object from an API result:
Dim myObj As clsServCasam()
Dim rsp As HttpWebResponse = CType(rq.GetResponse(), HttpWebResponse)
If rsp.StatusCode = HttpStatusCode.OK Then
Using sr = New StreamReader(rsp.GetResponseStream())
myObj = JsonConvert.DeserializeObject(Of clsServCasam())(sr.ReadToEnd())
End Using
Then I try to get the field names from the object:
For Each p As System.Reflection.PropertyInfo In myObj.GetType().GetProperties()
Debug.Print(p.Name, p.GetValue(myObj, Nothing))
Next
But, instead of class fields (ID, PRICE, ...) I got:
- Length
- LongLength
- Rank
Update
As Steven Doggart pointed out, the above loop won't work because it looks for properties rather than fields. So, I tried changing the loop to this:
For Each p As FieldInfo In myObj.GetType.GetFields()
Debug.Print(p.Name)
Next
But now I'm getting no results at all.
In your code, myObj is not declared as clsServCasam. Rather, it is declared as clsServCasam(), which means it's an array of clsServCasam objects. So, when you use reflection to iterate over its properties, you're getting the properties of the array rather than the actual clsServCasam type.
For instance, this would work more like you're expecting:
For Each item As clsServCasam in myObj
For Each p As PropertyInfo In item.GetType().GetProperties()
Debug.Print(p.Name, p.GetValue(item, Nothing))
Next
Next
However, I think you'll find that that still won't work because it iterates over the properties rather than the fields. In the definition of the clsServCasam class, all of the members are fields rather than properties, so the only properties that it have would be ones that are inherited from Object. You will need to either iterate over the fields using GetFields, like this:
For Each item As clsServCasam in myObj
For Each f As FieldInfo In item.GetType().GetFields()
Debug.Print(f.Name, f.GetValue(item))
Next
Next
Or you'll need to change them to properties:
Public Class clsServCasam
Public Property ID As Long
Public Property CANT As Decimal
Public Property PRICE As Decimal
End Class
Or, if you are using an older version of the VB compiler which doesn't support auto-properties:
Public Class clsServCasam
Public Property ID As Long
Get
Return _id
End Get
Set(value As Long)
_id = value
End Set
End Property
Public Property CANT As Decimal
Get
Return _cant
End Get
Set(value As Decimal)
_cant = value
End Set
End Property
Public Property PRICE As Decimal
Get
Return _price
End Get
Set(value As Decimal)
_price = value
End Set
End Property
Private _id As Long
Private _cant As Decimal
Private _price As Decimal
End Class

.Where method not defined on generic typed list?

When I try to use the .Where() method on a list, this does method does not seem to be defined if the list is of a generic type:
In my program, I have a class called Warning, and in another class, a list of warnings, defined as:
Dim warningList As List(Of Warning)
When I try to manipulate this list as:
Dim item = warningList.Where(Function(x) x.GetName() = "Foo").FirstOrDefault()
This works completely fine, but when I try it like this:
Dim itemList
if(type = "Warning") Then 'Please note that this condition is true...
itemList = warningList
End If
Dim item = itemList.Where(Function(x) x.GetName() = "Foo").FirstOrDefault()
I get an exception, stating that method .Where() is not defined for class Warning
Can anybody tell me why this is?
Thank you!
Now that you've edited your question it's clear.
You declare itemList without a type, so it's Object implicitly(in VB.NET with option strict set to Off which i strongly recommend against).
Now that you have declared a variable of type Object you can asssign any type to it. But you would have to cast it back to its real type List(Of Warning) to be able to use list or LINQ methods(which extend IEnumerable(Of T).
But instead declare it with the correct type:
Dim itemList As List(Of Warning)
if(type = "Warning") Then
itemList = warningList
End If
Dim item = itemList.Where(Function(x) x.GetName() = "Foo").FirstOrDefault()
Including to comment to explain why Warning is not related to this problem:
That's not the real code. If warningList is really a List(Of Warning)
you should be able to use Enumerable.Where(if LINQ is
imported). The fact that you assign this instance to another variable
(on declaration) doesn't change anything because that variable's type
is also a List(Of Warning). So itemList.Where should work too. Warning
has nothing to do with it because the type which is extended by Where
is IEnumerable(Of T), T can be any type(even Object). Since List(Of T)
implements IEnumerable(Of T) you can use Enumerable.Where on any list
(or array).
If you actually have multiple types and Warning is just one of it, you should implement a common interface. Here's an example:
Public Enum NotificationType
Warning
Info
[Error]
End Enum
Public Interface INamedNotification
ReadOnly Property Type As NotificationType
Property Name As string
End Interface
Public Class Warning
Implements INamedNotification
Public Sub New( name As String )
Me.Name = name
End Sub
Public Property Name As String Implements INamedNotification.Name
Public ReadOnly Property Type As NotificationType Implements INamedNotification.Type
Get
Return NotificationType.Warning
End Get
End Property
End Class
Now you can declare a List(Of INamedNotification) and fill it with whatever implements this interface, like the Warning class:
Dim notificationList As List(Of INamedNotification)
if type = "Warning" Then
itemList = warningList
Else If type = "Info"
itemList = infoList
End If
Dim item = notificationList.Where(Function(x) x.Name = "Foo").FirstOrDefault()

Returning Class Object from Inherited class

I'm trying to teach myself reflection and have been googling but I can't wrap my head around it entirely. I created a class called DataClass which contains a method called GetClassFromDB as you can see below, which will be inherited from multiple classes.
What I am attempting to do is have my dataclass read the TableName property that is defined within objResults. Once I pull in the tablename from objResults I would query the SQL database for a dataset. Once I have the dataset I would create a new object of the same TYPE inheriting this class (Which will be different types) and populate it from the dataset. Once I have the newly populated class I will return it for use.
I believe I have gotten most of the way there properly (Please correct me if there is a better way), but my real question is this. How can I create a new class of the type thats deriving that class from that string name that I getting in my code, or the type. I would want to have all the accessible properties from objResults available.
Namespace MyApp
Public Class DataClass
Private _TableName As String
Private _Name As String
Overridable ReadOnly Property TableName As String
Get
Return _TableName
End Get
End Property
Public Overloads Function GetClassFromDB() As Object
Try
Dim BaseObject As New Object
'Get the object name
Dim objName As String = MyBase.GetType().Name
'Gets the type thats calling this method
Dim objDerived As Type = MyBase.GetType()
'Get the property info to request the tablename from the derived class
Dim TableName As PropertyInfo = objDerived.GetProperty("TableName")
Dim TableNameString As String = TableName.GetValue(Me, Nothing).ToString
'Once I get the table name from objResults I can perform the SQL
Dim QueryResults as DataSet = SQLiteCLass.Query("Select * FROM TableNameString")
'Once I get data from the SQL I want to create a new object of the type deriving this method.
'In this example is objResults
Dim NewObject as objDerived
'Now I can fill my new object with the results and return it as an object
'THIS IS MY QUESTION - How can I create a new object of the TYPE that I receive from Reflection
Return False
Catch ex As Exception
Return False
End Try
End Function
End Class
End Namespace
and this is a sample class that would inherit my dataclass.
Public Class objResults
Inherits MyApp.DataClass
Private _GameID As Guid
Public Property GameID As Guid
Get
Return _GameID
End Get
Set(ByVal value As Guid)
_GameID = value
End Set
End Property
Public Overrides ReadOnly Property TableName As String
Get
Return "This is my tablename"
End Get
End Property
End Class
and this is how I would use this in code.
Dim objResult as New objResults
Dim TodaysResult as objResultsCollection
TodaysResult = objResult.GetClassFromDB()

How can I copy an object of an unknown type in VB.net?

Rather than giving the very specific case (which I did earlier), let me give a general example. Let's say that I have a function, called callingFunction. It has one parameter, called parameter. Parameter is of an unknown type. Let us then say that I wish to copy this parameter, and return it as a new object. For example, in pseudo code, something along the lines of...
Function callingFunction(ByVal parameter As Object) As Object
Dim newObj As New Object
'newObj has the same value as parameter, but is a distinctly different object
'with a different reference
newObj = parameter
return newObj
End Function
EDIT: Additional Information
The first time I posted this question, I received only one response - I felt that perhaps I made the question too specific. I guess I will explain more, perhaps that will help. I have an ASP page with 10 tables on it. I am trying, using the VB code behind, to come up with a single solution to add new rows to any table. When the user clicks a button, a generic "add row" function should be called.
The difficulty lies in the fact that I have no guarantee of the contents of any table. A new row will have the same contents as the row above it, but given that there are 10 tables, 1 row could contain any number of objects - text boxes, check boxes, etc. So I want to create a generic object, make it of the same type as the row above it, then add it to a new cell, then to a new row, then to the table.
I've tested it thoroughly, and the only part my code is failing on lies in this dynamic generation of an object type. Hence why I asked about copying objects. Neither of the solutions posted so far work correctly, by the way. Thank you for your help so far, perhaps this additional information will make it easier to provide advice?
You can't do this in general. And it won't be a good idea, for example, if parameter is of a type which implements the singleton pattern. If parameter is of a type which supports copying, it should implement the ICloneable interface. So, your function could look like this:
Function MyFunc(ByVal parameter As Object) As Object
Dim cloneableObject As ICloneable = TryCast(parameter, ICloneable)
If Not cloneableObject Is Nothing Then
Return cloneableObject.Clone()
Else
Return Nothing
End If
End Function
You could implement something like this:
Dim p1 As Person = New Person("Tim")
Dim p2 As Object = CloneObject(p1)
Dim sameRef As Boolean = p2 Is p1 'false'
Private Function CloneObject(ByVal o As Object) As Object
Dim retObject As Object
Try
Dim objType As Type = o.GetType
Dim properties() As Reflection.PropertyInfo = objType.GetProperties
retObject = objType.InvokeMember("", System.Reflection.BindingFlags.CreateInstance, Nothing, o, Nothing)
For Each propertyInfo As PropertyInfo In properties
If (propertyInfo.CanWrite) Then
propertyInfo.SetValue(retObject, propertyInfo.GetValue(o, Nothing), Nothing)
End If
Next
Catch ex As Exception
retObject = o
End Try
Return retObject
End Function
Class Person
Private _name As String
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Public Sub New()
End Sub
Public Sub New(ByVal name As String)
Me.Name = name
End Sub
End Class
Here's a simple class that will work for most objects (assumes at least .Net 2.0):
Public Class ObjectCloner
Public Shared Function Clone(Of T)(ByVal obj As T) As T
Using buffer As MemoryStream = New MemoryStream
Dim formatter As New BinaryFormatter
formatter.Serialize(buffer, obj)
buffer.Position = 0
Return DirectCast(formatter.Deserialize(buffer), T)
End Using
End Function
End Class