I would like to know if its possible to write multiple lines, the equivalent of this line bellow, but instead of using With and From use multiple lines to declare data.
Dim Price = New PriceStruc() With { _
.Bids = New List(Of Prices)() From {New Prices() With {.Price = 1101, .Size = 1}},
.Offers = New List(Of Prices)() From {New Prices() With {.Price = 1102, .Size = 1}}}
You can add parameters to the constructor to set properties when you create an instance. This is especially helpful for an object which should only exist when this or that property is known. Another use in designer serialization, among others.
Warning: taking it as far as requested doesnt make the code any easier to read
I dont know exactly what these are, so I made up my own and fixed some of the nomenclature (it looks like Prices has data for one item, yet it is plural).
Friend Class Price
Public Property Value As Integer
Public Property Size As Integer
Public Sub New()
End Sub
Public Sub New(v As Integer, s As Integer)
Value = v
Size = s
End Sub
End Class
The simple constructor (no params) is there because many serializers require one. Depending on the serializer, you can it set it as Friend to force your code to use the overload and specify Value and Size when you create an new Price object. This is useful when an object has no right being created without certain key information. (You can still use it in For Each loops because you do not need a new object for that).
In this case, the Value (named to avoid Price.Price) and Size might be required elements, but the constructor overload is mainly a convenience. To use it:
Dim p As New Price(1101, 1)
Now, those objects can be instanced without With. The holder looks like this:
Friend Class PriceItem
Public Property Bids As List(Of Price)
Public Property Offers As List(Of Price)
Public Sub New()
End Sub
Public Sub New(b As List(Of Price), o As List(Of Price))
Bids = b
Offers = o
End Sub
End Class
There is likely more to it, like a Name indicating what the Bids and Offers are for, but the idea is the same: pass the lists in the constructor.
Now you can initialize the Price objects and PriceItem using their constructors:
Dim Prices = New PriceItem(New List(Of Price)(New Price() {New Price(1101, 1),
New Price(1102, 1)}),
New List(Of Price)(New Price() {New Price(1106, 7),
New Price(1104, 1)}))
No With
No From
1101 and 1102 are the Bid items, 1106 and 1104 are the offer items.
As I said, it doesnt make it any easier to read, debug or code. It perhaps makes sense for a Price item but passing lists to the PriceItem ctor seems a bit much. Rather than trying to squeeze everything into the initialization, this seems to strike the best balance between readability and conciseness:
Dim PItem As New PriceItem
PItem.Bids = New List(Of Price)(New Price() {New Price(1101, 1), New Price(1102, 1)})
PItem.Offers = New List(Of Price)(New Price() {New Price(1106, 7), New Price(1104, 1)})
No With
No From
Related
I want to make a collection to have data available
Example:
Dim b As New Collection
colb = New Collection
b.Add("system", "1001", "SYSTEM")
b.Add("network", "1002", "NETWORKA")
b.Add("networksecond", "1010", "NETWORKB")
colb.Add(b, "list")
im looking for a function to get data from this collection:
I want to, based on the ID (Second number) get the first and third value
So if I search for 1010, I need to have the value Network and NETWORKA
VB6 called, they want their Collection back.
No, seriously, please consider using a Dictionary instead of the old, legacy Collection class. Behold the beauty of generics and strong typing:
Dim dic As New Dictionary(Of Integer, Tuple(Of String, String))
dic.Add(1001, Tuple.Create("system", "SYSTEM"))
dic.Add(1002, Tuple.Create("network", "NETWORKA"))
dic.Add(1010, Tuple.Create("networksecond", "NETWORKB"))
' Search
Dim t As Tuple(Of String, String) = Nothing
If dic.TryGetValue(1002, t) Then
Console.WriteLine(t.Item1) ' prints "network"
Console.WriteLine(t.Item2) ' prints "NETWORKA"
End If
As soon as you have more than two values, I suggest that you use a specialized class instead of a Tuple to increase readability.
Also, you can simply use List(Of T). In most cases this is enough. Dictionary is good for fast search out long list by a single key.
'declare model
Public Class NetworkModel
Public Property Id As Integer
Public Property Name1 As String
Public Property Name2 As String
End Class
' load list of models
Private _modelList As New List(Of NetworkModel)()
.......
' search using LINQ
Dim model As NetworkModel = _modelList.FirstOrDefault(Function(m) m.Id = 1001)
If model IsNot Nothing Then . . . . .
I've done some reading and cant seem to wrap my head around what the best approach would be to clone a List(of class) in my VB2010 project. I have three classes that are related like so
Public Class City
'here are many fields of type string and integer
Public Roads As New List(Of Road)
End Class
Public Class Road
'here are many fields of type string and integer
Public Hazards As New List(Of Hazard)
End Class
Public Class Hazard
Implements ICloneable
'here are many fields of type string and integer and double
Public Function Clone() As Object Implements System.ICloneable.Clone
Return Me.MemberwiseClone
End Function
End Class
So lets say I have a city I'm working on, there are cases where I want to create, as a base one road and its hazards, then add another road but using the prior roads hazards as a starting point and then tweak the fields.
Dim rd As New Road
'add road fields
dim hz1 as New Hazard
'add hazard fields
dim hz2 as New Hazard
'add hazard fields
'add the hazard objects to the road
rd.Hazards.Add(hz1)
rd.Hazards.Add(hz2)
'add the road to the city
myCity.Roads.Add(rd)
'here I want to start a new road based on the old road
Dim rdNew As New Road
'copy or clone the hazards from old road
rdNew.Hazards = rd.Hazards '<============
'over-write some of the hazard fields
rdNew.Hazards(0).Description = "temp"
So I know that copying a class will copy the pointer and not the contents. I used the ICloneable interface in the hazard class but cant say I'm using it right. The Hazards variable is a list of Hazard class. How would i go about cloning that class?
Implementing IClonable doesn't mean that it replaces the regular assignment, it will still just copy the reference. And you aren't even copying the items, you are copying the list, which means that you still only have one list, but two references to it.
To use the Clone method you have to call it for each item in the list:
rdNew.Hazards = rd.Hazards.Select(Function(x) x.Clone()).Cast(Of Hazard).ToList()
Imports System.IO
Imports System.Xml.Serialization
Public Function CopyList(Of T)(oldList As List(Of T)) As List(Of T)
'Serialize
Dim xmlString As String = ""
Dim string_writer As New StringWriter
Dim xml_serializer As New XmlSerializer(GetType(List(Of T)))
xml_serializer.Serialize(string_writer, oldList)
xmlString = string_writer.ToString()
'Deserialize
Dim string_reader As New StringReader(xmlString)
Dim newList As List(Of T)
newList = DirectCast(xml_serializer.Deserialize(string_reader), List(Of T))
string_reader.Close()
Return newList
End Function
I know this is old.
rdNew.Hazards = rd.Hazards.ToList()
Even though it's already a list, ToList will create a new list based on it.
With VB 2019, this will create a shallow copy, but that's useful in some circumstances. That means that the list is new, but the elements of both rd.Hazards and rdNew.Hazards point to the same thing.
If you edit any particular hazard, the changes will be seen in both.
If you add a hazard to one list, the other list will not have it.
If you delete a hazard from one list, the other list will still have it.
If Hazard were a primitive type (like a string or integer), then editing items would not be reflected in the other list.
I'm stuck with the following problem. I have a class with a constructor (a New(<args>) method). I also have a List of objects of this class that I'd like to populate. To give an example, here's some toy code (avoiding properties and such):
Class Thing
Public PositionX, PositionY As UInteger
Public Name As String
Public Sub New(ByVal name As String, _
ByVal positionX As UInteger, _
ByVal positionY As UInteger)
Me.PositionX = positionX
Me.PositionY = positionY
Me.Name = name
End Sub
End Class
Also, elsewhere in code I'm declaring a list of Things:
Dim things As List(Of Thing)
When trying to run the following line of code, things.Add(New Thing("some name', 1, 1)), I get a Object reference not set to an instance of an object exception. Clearly, I have a misunderstanding of what an instance of an object really is and how VB.NET goes about working with them. I guess it goes back to my C/C++ background.
Of course, I could initialize a variable with the New constructor, and then add it to the list:
The following does not work either:
Dim myThing = New Thing("some name", 1, 1)
things.Add(myThing)
My question is why does simply saying New Thing("some name', 1, 1) does not create an instance of Thing what what is the right way to think about such things? Anything I'm doing wrong by design?
Cheers!
Looks to me like you just need to instance your list:
Dim things As New List(Of Thing)
I think everything is fine with the handling of the thing class, but the list needs an instance too - Its a class/instance just like the things are.
You need to do:
Dim things as New List(Of Thing)
or:
Dim things as List(Of Thing)
things=New List(Of Thing)
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
I am not sure how to phrase my question properly but I want to achieve something like this.
I have a class named Products
public class Products
private ID as Integer
private Name as String
Public Property ProductID()
Get
Return ID
End Get
Set(ByVal value)
ID = value
End Set
End Property
In one of my code behind pages, I am retrieving data from an SQL Command and placing the same into a datareader object.
How would I be able to declare the class so that each row in my datareader would actually be an instance of the said class?
Like for example:
Dim myProduct() as New Product
Dim intCnt as Integer
While datareaderData.read()
intCnt += 1
myProduct(intCnt) = new Product
myProduct(intCnt).ID = datareaderData("ID")
myProduct(intCnt).Name = datareaderData("Name")
End While
When I do the same, I am getting an error "Object Reference Not Set to an Instance of an Object.
I am quite stumped on this one. Any tips greatly appreciated. Thanks.
You should use an Arraylist or -better- a generic List(of Product).
Besides i would strongly recommend to set Option Strict On in your project's Compiler Settings.
Dim products As New List(Of Product)
While datareaderData.read()
Dim nextProduct As New Product
nextProduct.ProductID = CType(datareaderData("ID"), System.Int32)
nextProduct.Name = datareaderData("Name").ToString
products.add(nextProduct)
End While