(De)Serializing in VB.Net - vb.net

I have written a class (containing only properties). The code is shortened, here is only the part of the code what I want to do:
Public Class test
Public Overrides Function ToString() As String
'Das Objekt lebensmittel serialisieren
Dim ser As New Xml.Serialization.XmlSerializer(Me.GetType)
Dim sw As New IO.StringWriter
ser.Serialize(sw, Me)
Return sw.tostring
End Function
Public Sub New()
End Sub
Public Sub New(ByVal t As String)
Dim deser As New Xml.Serialization.XmlSerializer(Me.GetType)
Dim ms As New IO.MemoryStream(System.Text.Encoding.Unicode.GetBytes(t))
Me = CType(deser.Deserialize(ms), test) 'This throws an error
End Sub
End Class
What I want to do is to overload the New() operator and deserialize the string to this class, like:
Dim x As New test(string)
How can I do this? The marked line throws an error in Sub New.

Related

Assigning class Instance to Interface

Have two questions regarding the code below:
In the following code, the class Test implement the interface Test_Interafce. I have read in more than one articles that when a class implements an interface, we should assign the class instance to the interface. Going by that in the following code the statement Dim t As New Test() should be replaced by Dim t As Test_Interface = New Test(). However I do not understand the advantage or need for the same. When I instantiate the class Test by simply writing Dim t As New Test(), I am able to access all elements (even the procedures of the interface implemented by the class) through the instance "t" and the code seems to be working fine. So then why to assign a class instance to an interface?
Infact if I write Dim t As Test_Interface = New Test() then through "t" does not allow me to access the subroutine CHECK in the class Test. The error being displayed is: "CHECK is not a member of Test_Interface". So isnt that a disadvantage??!!
What is the use of the statement: Throw New NotImplementedException(). This statement comes automatically when I implement teh interface in a class/structure.
The code is found below:
Module Module1
Interface Test_Interface
Function Length(ByVal s As String) As Integer
Sub Details(ByVal age As Integer, ByVal name As String)
End Interface
Sub Main()
Dim t As New Test() 'Alternate definition: Dim t As Test_Interface = New Test()
t.Details(31, "Mounisha")
Console.WriteLine("Length of the string entered = {0}", t.Length("Hello"))
t.check()
Console.ReadLine()
End Sub
End Module
Class Test
Implements Test_Interface
Public Sub Details(age As Integer, name As String) Implements Test_Interface.Details
Console.WriteLine("Age of person = {0}", age)
Console.WriteLine("Name of person = {0}", name)
'Throw New NotImplementedException() ----> what does this do?
End Sub
Public Function Length(s As String) As Integer Implements Test_Interface.Length
Console.WriteLine("Original String: {0}", s)
Return s.Length()
'Throw New NotImplementedException()
End Function
Sub check()
Console.WriteLine("The sub can be accessed")
End Sub
End Class

VB.net how do I combine lists and classses?

Here are my definitions:
Public Class RouteDetails
Public strRoad As String
Public strToLane As String
Public strToDirection As String
End Class
Public Class Route
Public lstRouteDetails As List(Of RouteDetails)
End Class
ByVal lstRouteList As List(Of Route) (part of a function definition)
Sorry I tried to put the definitions section into a code block but, for some reason, it's not working.
Here is a section of the code, from that function, that I'm having problems with:
rlcRoute = New Route
lstRouteList.Add(rlcRoute)
rdcRouteStep.strRoad = sdrNextJunction.GetValue(3)
rdcRouteStep.strToLane = sdrNextJunction.GetValue(2)
rdcRouteStep.strToDirection = sdrNextJunction.GetValue(1)
For intloop = 0 To lstRouteList.Count - 1
lstRouteList(intloop).lstRouteDetails.Add(rdcRouteStep)
Next
The line, within the for loop, fails with:
System.NullReferenceException: 'Object reference not set to an
instance of an object.'
System.Collections.Generic.List.this[int].get.lstRouteDetails was
Nothing.
If I understand the error correctly then it's telling me that I haven't created an instance of lstRouteDetails for this instance of Route? If that's correct then I would
appreciate some advice on how to achieve this? I've tried a few combinations. The structure I'm trying to have is as follows:
RouteList is a list of objects of type route
Each Route object contains several objects of type RouteDetails
Thanks
You don't need a class for you list. You can just create one in your form.
I added a custom constructor to your class so you can set all the properties of the class in one line as demonstrated in the BuildList Sub. I had to add back the default constructor (no parameters). With the default constructor the properties are set individually. I also added an override of the .ToString method so we could use it in the Form. (See the OPCode method)
The Class
Public Class RouteDetails
Public strRoad As String
Public strToLane As String
Public strToDirection As String
Public Sub New()
End Sub
Public Sub New(Road As String, ToLane As String, Direction As String)
strRoad = Road
strToLane = ToLane
strToDirection = Direction
End Sub
Public Overrides Function ToString() As String
Return $"Road is {strRoad}, Lane is {strToLane}, Direction is {strToDirection}"
End Function
End Class
The Form
Private RouteList As New List(Of RouteDetails)
Private Sub BuildList_Click(sender As Object, e As EventArgs) Handles MyBase.Load
Dim Route As New RouteDetails()
Route.strRoad = "Main Street"
Route.strToLane = "Park Lane"
Route.strToDirection = "North East"
RouteList.Add(Route)
'or with the custom constructor
Dim Route2 As New RouteDetails("Wall Steet", "Mulberry Lane", "South West")
RouteList.Add(Route2)
End Sub
You can refer to the items in the list anywhere in the form.
Private Sub OPCode()
MessageBox.Show(RouteList(1).strToLane)
For Each item As RouteDetails In RouteList
ListBox1.Items.Add(item) 'The ListBox calls .ToString on the item for display
Next
End Sub
EDIT
Expanded Code
Public Class Route
Public RouteDetailsList As New List(Of RouteDetails)
Public Name As String
Public Sub New(RDL As List(Of RouteDetails), nme As String)
RouteDetailsList = RDL
Name = nme
End Sub
Public Sub New()
End Sub
Public Overrides Function ToString() As String
Return Name
End Function
End Class
To test the code
In the Form_Load call BuildRouteList
Private RouteList As New List(Of Route)
Private Sub BuildRouteList()
Dim Details = {New RouteDetails("MainStreet", "Park Lane", "North East"), New RouteDetails("Wall Steet", "Mulberry Lane", "South West")}
'Uses the construtor List(Of T)(IEnumerable<T>)
Dim R As New Route(New List(Of RouteDetails)(Details), "1")
RouteList.Add(R)
Dim Details2 = {New RouteDetails("Wall Street", "Strawberry Lane", "South West"), New RouteDetails("Pine Street", "Little Maid Lawnd", "North")}
Dim R2 As New Route(New List(Of RouteDetails)(Details2), "2")
RouteList.Add(R2)
End Sub
In a button click call OPCode1 (assumes a ListBox1 is present
Private Sub OPCode1()
MessageBox.Show(RouteList(0).RouteDetailsList(1).strToLane) 'shows Mulberry Lane
For Each item As Route In RouteList
ListBox1.Items.Add(item)
For Each route In item.RouteDetailsList
ListBox1.Items.Add(route) 'The ListBox calls .ToString on the item for display
Next
Next
End Sub

how to get the Index of object in collection

I'm trying to make a application, in this application I have a List(of T) collection that holds an object.
When processing the object I need to know it's Index from the list.
Example:
Public Class
Public oList as New List(of TestObject)
Private Sub Test()
Dim NewObject As New TestObject
oList.add(NewObject)
Index(NewObject)
End Sub
Private Sub Index(Byval TestObject As TestObject)
debug.print(Testobject.index)
End Sub
End Class
Is something like this possible? Ive seen it available in a reference file I used some time ago, but now I would like to make this available within my own class.
Can someone provide a sample?
PS: I know I can get the index using the List(Of T).IndexOf Method (T) but for future possibilities I would like to make the call from the object itself.
What usually happen is that they have a custom list, they don't directly used List(Of T) and store the list inside the object when they add that item to the list.
Module Module1
Sub Main()
Dim someList As New CustomList
someList.Add(New CustomItem())
someList.Add(New CustomItem())
someList.Add(New CustomItem())
Console.WriteLine(someList(1).Index)
Console.ReadLine()
End Sub
End Module
Class CustomItem
' Friend since we don't want anyone else to see/change it.
Friend IncludedInList As CustomList
Public ReadOnly Property Index
Get
If IncludedInList Is Nothing Then
Return -1
End If
Return IncludedInList.IndexOf(Me)
End Get
End Property
End Class
Class CustomList
Inherits System.Collections.ObjectModel.Collection(Of CustomItem)
Protected Overrides Sub InsertItem(index As Integer, item As CustomItem)
If item.IncludedInList IsNot Nothing Then
Throw New ArgumentException("Item already in a list")
End If
item.IncludedInList = Me
MyBase.InsertItem(index, item)
End Sub
Protected Overrides Sub RemoveItem(index As Integer)
Me(index).IncludedInList = Nothing
MyBase.RemoveItem(index)
End Sub
End Class
It looks like this
Public oList As New List(Of TestObject)
Private Sub Test()
Dim NewObject As New TestObject(oList.Count)
oList.add(NewObject)
End Sub
Public Class TestObject
Public index As Integer
Public Sub New(IndxOfObj As Integer)
Me.index = IndxOfObj
End Sub
End Class
If you necessarily need to have it as a property on the object I would suggest the following:
Public Class Main
Public oList As New List(Of TestObject)
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Dim NewObject As New TestObject(Me)
oList.Add(NewObject)
Dim NewObject2 As New TestObject(Me)
oList.Add(NewObject2)
MsgBox(NewObject2.Index)
End Sub
Public Function Index(ByVal TestObject As TestObject) As Integer
Return oList.IndexOf(TestObject)
End Function
End Class
Public Class TestObject
Private _main As Main
Public ReadOnly Property Index() As Integer
Get
Return _main.Index(Me)
End Get
End Property
Public Sub New(RootClass As Main)
_main = RootClass
End Sub
End Class
If you happen to have the Main class as a Singleton you can skip the whole sending 'Me' into the constructor business. Then you can just call Main.Index without storing it as a property on all TestObjects.

A class can only be a template for a single object not a template for a collection

I have a simple class List.vb which is the following:
Public Class List
Public fList As List(Of Integer)
Public Sub New()
fList = New List(Of Integer)
fList.Add(1)
fList.Add(2)
fList.Add(3)
fList.Add(4)
fList.Add(5)
End Sub
End Class
The Console application is using this class like the following:
Module Module1
Sub Main()
Dim fObject As List = New List
Dim cnt As Integer = 0
For Each x As Integer In fObject.fList
Console.WriteLine("hello; {0}", fObject.fList.Item(cnt).ToString())
cnt = cnt + 1
Next
Console.WriteLine("press [enter] to exit")
Console.Read()
End Sub
End Module
Can I change the class code so that List.vb is a list(of integer) type?
This would mean that in the Console code I could replace In fObject.fList with just In fObject?
Or am I barking up the wrong tree - should classes be single objects and lists should be collections of classes ?
Yes, you can do that. In order for an object to be compatible with For Each, it must have a GetEnumerator function:
Public Function GetEnumerator() As IEnumerator _
Implements IEnumerable.GetEnumerator
Return New IntListEnum(fList)
End Function
The IntListEnum class must, in turn, implement IEnumerator, like this:
Public Class IntListEnum Implements IEnumerator
Private listInt As List(Of Integer)
Dim position As Integer = -1
Public Sub New(ByVal fList As List(Of Integer))
listInt = fList
End Sub
Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
position = position + 1
Return (position < listInt.Count)
End Function
Public Sub Reset() Implements IEnumerator.Reset
position = -1
End Sub
Public ReadOnly Property Current() As Object Implements IEnumerator.Current
Get
Try
Return listInt(position)
Catch ex As IndexOutOfRangeException
Throw New InvalidOperationException()
End Try
End Get
End Property
End Class
Now you can make fList private, and iterate your List as follows:
For Each x As Integer In fObject
You can see a complete example here.
The answer that dasblinkenlight has provided is excellent, but if all you need is a list that of integers that is pre-populated, you can just inherit from List(Of Integer) and then have the class populate itself in the constructor:
Public Class List
Inherits List(Of Integer)
Public Sub New()
Add(1)
Add(2)
Add(3)
Add(4)
Add(5)
End Sub
End Class
When you inherit from List(Of Integer), your class automatically gets all of the functionality implemented by that type, so your class also becomes a list class that works the same way. Then, you can just use it like this:
Dim fObject As New List()
For Each x As Integer In fObject
Console.WriteLine("hello; {0}", x)
Next

VB.NET: How can I have events return a value like I can in C#?

In C#, I can do this:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Class1 c1 = new Class1();
c1.OnNeedInt += new Class1.NeedInt(c1_OnNeedInt);
int i = c1.GetInt();
}
int c1_OnNeedInt()
{
return 1;
}
}
public class Class1
{
public delegate int NeedInt();
public event NeedInt OnNeedInt;
public int GetInt()
{
return OnNeedInt == null ? 0 : OnNeedInt();
}
}
Notice the line int i = c1.GetInt();. I can't seem to get VB.NET 4.0 to do something similiar. Any help?
I thinks its even easier than most people think...
Class MyClass
Public Event MyEvent(ByRef MyVariable as String)
Private Sub DoSomething()
Dim SomethingINeed as String = String.Empty
RaiseEvent MyEvent(SomethingINeed)
'SomethingINeed will now contain "Goodbye Cruel World"
End sub
End Class
Then in the class that monitors the event...
Class MyOtherClass
Private Sub New()
AddHandler MyClass.MyEvent, Addressof MyEventHandler
End Sub
Private Sub MyEventHandler(ByRef StringToPassBack as String)
StringToPassBack = "Goodbye Cruel World"
End Sub
End Class
It's all about the ByRef keywords in both the event declaration and the eventhandler sub.
That's not possible in vb.net, events must be raised with the RaiseEvent statement. It doesn't return a value. It is a pretty questionable practice anyway, an event can have zero or multiple subscribers. No telling what the return value might be. Just use a delegate instead:
Class Page
Public Sub New()
Dim obj As New Class1
Dim dlg As New Func(Of Integer)(AddressOf obj.GetInt)
Dim i As Integer = dlg()
End Sub
End Class
Class Class1
Public Function GetInt() As Integer
Return 42
End Function
End Class
In VB, you don't need to check to see if anyone is attached to your event handler. You can just call RaiseEvent and if anyone is listening to it, it will work. However, the event isn't intended to return a value. You could try sticking it into an event arg and pass that around, but that gets messy.
#HansPassant's solution is close, but not quite what you were asking for. Altering his solution a bit:
Delegate Function FetchIt() As Integer
Class Page
Public Sub New()
Dim obj As New Class1
Dim i As Integer = obj.GetInt(AddressOf c1_OnNeedInt)
End Sub
Function c1_OnNeedInt() As Integer
Return 42
End Function
End Class
Class Class1
Public Function GetInt(fetcher As FetchIt) As Integer
Return fetcher()
End Function
End Class
Alternatively, you could do this without the custom delegate using Lambda's:
Class Page
Public Sub New()
Dim obj As New Class1
Dim dlg As New Func(Of Integer)(AddressOf c1_OnNeedInt)
Dim i As Integer = obj.GetInt(dlg)
End Sub
Function c1_OnNeedInt() As Integer
Return 42
End Function
End Class
Class Class1
Public Function GetInt(fetcher As Func(Of Integer)) As Integer
Return fetcher()
End Function
End Class
I found an answer to my issue. In the base class that my ASP.NET user controls inherit, I have this:
Dim _Connection As MyConnection
Public Property Connection As MyConnection
Get
If _Connection Is Nothing Then
RaiseEvent OnNeedConnection(_Connection)
End If
Return _Connection
End Get
Set(value As MyConnection)
_Connection = value
End Set
End Property
Public Delegate Sub NeedConnection(ByRef Connection As MyConnection)
Public Event OnNeedConnection As NeedConnection
In my web form codebehind, I wire it up manually to this:
Sub ServeConnection(ByRef Connection As MyConnection)
Connection = oConn
End Sub
The actual connection is hosted on the webform's codebehind, but I have several user controls that need to use this connection. Any time any of the user controls need the connection, their base class requests it and the host page serves it. This is made possible by the ByRef keyword.
This is the closest C# equivalent I could put together.