Pergunta

I am new to vb.net, and this is my first project where I'm fairly certain there is an obvious answer that I just can't find.

Problem: I have a list of a structure I have defined with many properties. I want to be able to edit and load that list with the values I have saved to it before hand after closing the program and loading it backup. What is the best way to do this?

This isn't a simple string or bool, otherwise I would use the user settings that is commonly suggested, in the project's properties. I've seen others that save it into an xml and take it back up, but I'm not inclined to do so since this is going to be distributed to others in mass. Since it's a complex structure, what's the commonly held preferred method?

Example

Here's a structure:

Structure animal
 Dim coloring as string 
 Dim vaccinesUpToDate as Boolean
 Dim species as string 
 Dim age as integer 
End structure 

And there's a List(Of animal) that the user will add say 1 cat, 2 dogs, etc. I want it so that once the programs is closed after the user has added these, that structure will be saved to still have that 1 cat and 2 dogs with those settings so I can display them again. What's the best way to save the data in my program? Thanks!

Foi útil?

Solução

Consider serialization. For this, a class is more in order than an old fashioned Struct:

<Serializable>
Class Animal
    Public Property Name As String
    Public Property Coloring As String
    Public Property VaccinesUpToDate As Boolean
    Public Property Species As String   
    Public Property DateOfBirth As DateTime

    Public ReadOnly Property Age As Integer
        Get
            If DateOfBirth <> DateTime.MinValue Then
                Return (DateTime.Now.Year - DateOfBirth.Year)
            Else
                Return 0   ' unknown
            End If
    End Get
    End Property

    ' many serializers require a simple CTor
    Public Sub New()

    End Sub

    Public Overrides Function ToString() As String
        Return String.Format("{0} ({1}, {2})", Name, Species, Age)
    End Function
End Class

The ToString() override can be important. It is what will display if you add Animal objects to a ListBox e.g.: "Stripe (Gremlin, 27)"

Friend animalList As New List(of Animal)   ' a place to store animals

' create an animal
a = New Animal
a.Coloring = "Orange"
a.Species = "Feline"       ' should be an Enum maybe
a.Name = "Ziggy"
a.BirthDate = #2/11/2010#

animalList.Add(a)
' animalList(0) is now the Ziggy record. add as many as you like.

In more complex apps, you might write an Animals collection class. In that case, the List might be internal and the collection could save/load the list.

Friend Sub SaveData(fileName as String)
    Using fs As New System.IO.FileStream(fileName,
        IO.FileMode.OpenOrCreate)

        Dim bf As New BinaryFormatter
        bf.Serialize(fs, animalList)
   End Using
End Sub

Friend Function LoadData(fileName as String) As List(Of Animal)
     Dim a As List(of Animal)
     Using fs As New FileStream(fileName, FileMode.Open, FileAccess.Read)
        Dim bf As New BinaryFormatter
        a = CType(bf.Deserialize(fs), List(Of Animal))
    End Using
    Return a
End Function

XMLSerialization, ProtoBuf and even json are much the same syntax. For a small amount of data, a serialized list is an easy alternative to a database (and have many, many other uses, like a better Settings approach).

Calculated Fields as Properties

Notice that I added a BirthDate property and changed Age to calculate the result. You should not save anything which can be easily calculated: in order to update the Age (or VaccinesUpToDate) you'd have to 'visit' each record, perform a calculation then save the result - which might be wrong in 24 hours.

The reason for exposing Age as a Property (rather than a function) is for data binding. It is very common to use a List<T> as the DataSource:

animalsDGV.DataSource = myAnimals

The result will be a row for each animal with each Property as a column. Fields as in the original Structure won't show up. Nor would an Age() function display, wrapping the result as a readonly property displays it. In a PropertyGrid, it will show disabled because it is RO.

Class versus Structure

So if a Structure using Properties will work, why use a Class instead? From Choosing Between Class and Struct on MSDN, avoid using a Structure unless the type meets all of the following:

  1. It logically represents a single value, similar to primitive types (int, double, etc.)
  2. It has an instance size under 16 bytes
  3. It is immutable
  4. It will not have to be boxed frequently

Animal fails the first 3 points (while it is a local item it is not a value for #1). It may also fail the last depending on how it is used.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top