Home > Articles > Programming > Windows Programming

  • Print
  • + Share This
Like this article? We recommend

Saving Different Data

The preceding examples demonstrate saving a single class of data. Your own program might be more complex, however, in that the users might be working with different types of data, as well as different amounts of data. For example, a vector drawing program would let the user create many different vector drawing objects. This isn’t a matter of a single class being saved—at least, it might not seem like it. In fact, however, the same code will work. The reason is that the serialization features in .NET allow for collections to be saved. All you need to do is gather all your data into a collection object, and then serialize the collection.

Following is a complete program that demonstrates this principle:

Option Strict On
Imports System.IO
Module Module1

  <Serializable()> Class MemberInfo
    Public FirstName As String
    Public LastName As String
    Public Birth As DateTime
    Public Sub New(ByVal FN As String, _
    ByVal LN As String, ByVal Bth As DateTime)
      FirstName = FN
      LastName = LN
      Birth = Bth
    End Sub
    Public Sub Show()
      Console.WriteLine(String.Format("  {0} {1}: {2}", _
        FirstName, LastName, Birth))
    End Sub
  End Class

  <Serializable()> Class WebSiteInfo
    Public Title As String
    Public Description As String
    Public Address As Uri
    Public Sub New(ByVal Tt As String, _
    ByVal De As String, ByVal Ad As Uri)
      Title = Tt
      Description = De
      Address = Ad
    End Sub
    Public Sub Show()
      Console.WriteLine(String.Format("  {0} {1}: {2}", _
        Title, Description, Address))
    End Sub
  End Class

  Sub Main()
    Dim UserData As New ArrayList
    UserData.Add(New MemberInfo("Sam", "Smith", _
      New DateTime(1968, 8, 13)))
    UserData.Add(New MemberInfo("Julie", "Jones", _
      New DateTime(1972, 9, 15)))
    UserData.Add(New WebSiteInfo("CNN", "News", _
      New Uri("http://www.cnn.com")))
    UserData.Add(New WebSiteInfo("Yahoo", "Search engine", _
      New Uri("http://www.yahoo.com")))

    Dim formatter As New _
      Runtime.Serialization.Formatters.Binary.BinaryFormatter
    Dim stream As New FileStream("c:\temp\userdata.dat", _
      FileMode.Create, FileAccess.Write, FileShare.None)
    formatter.Serialize(stream, UserData)
    stream.Close()

    ’ Now read the data back in to another list

    Dim readdata As New ArrayList
    Dim readformatter As New _
      Runtime.Serialization.Formatters.Binary.BinaryFormatter
    Dim readstream As New FileStream("c:\temp\userdata.dat", _
      FileMode.Open, FileAccess.Read, FileShare.Read)

    readdata = CType(formatter.Deserialize(readstream), ArrayList)
    stream.Close()

    ’ Display the data to see if it worked

    Dim obj As Object
    For Each obj In readdata
      If TypeOf (obj) Is MemberInfo Then
        Console.WriteLine("MemberInfo")
        CType(obj, MemberInfo).Show()
      ElseIf TypeOf (obj) Is WebSiteInfo Then
        Console.WriteLine("WebSiteInfo")
        CType(obj, WebSiteInfo).Show()
      End If
    Next

  End Sub

End Module

This code declares two different types of data, MemberInfo and WebSiteInfo. The program creates an ArrayList and fills the list with a random mixture of MemberInfo and WebSiteInfo objects. Then the code uses the same technique as described earlier to stream out the data, by writing the ArrayList collection to the stream. Notice that in order for this to work, I had to mark the individual classes with the Serializable attribute. (The ArrayList class is already serializable.)

Reading the data in is also just like the previous example. However, once the data is read back in, I needed to jump through some hoops to analyze the data. Since this is a sample program, I know what data I put in; however, in a real program, I might not know exactly what data is in the list I read back in. So I wrote this sample code as if I didn’t know what data to expect, checking the types of the instances. Notice that I’m calling TypeOf and testing the type against my two classes.

However, in this case all I’m doing is calling member functions to write out the data. Both classes have a member function called Show. What I could have done, then, is to derive both classes from a common class that provides an overrideable method called Show. Then I could cast the incoming data to that base class, and just call Show. That would alleviate the need to check the type.

Also, Visual Basic .NET allows for late binding. A lot of people don’t realize that you can do this, but if you turn off the Option Strict (by removing the line altogether or by replacing On with Off), you can simply store the incoming objects in an instance of type Object. Then you just make the call to the Show method without even testing the type:

Dim obj As Object
For Each obj In readdata
  obj.Show()
Next

Yes, the compiler allows that. You can put any name you want after the obj, and the compiler will allow it. Only when the program runs will the .NET runtime determine whether the object has the member you’re trying to call. For example, if I called obj.Abcdef(), the compiler will build it just fine. After I run it, I’ll find out that the object doesn’t have an Abcdef member, and I’ll get an exception error:

Public member ’Abcdef’ on type ’MemberInfo’ not found.

In general, such late binding is bad programming style. However, it may be acceptable in your situation.

  • + Share This
  • 🔖 Save To Your Account