List<>...the saving of

  • Thread starter Thread starter mick
  • Start date Start date
M

mick

The next thing Ive learning about is Lists and generic Lists in particular and
one thing I`ve been wondering is how you actually save these lists so that
the contents are available the next time you run the app. Ive had a quick
google and come across Serialization (binary) which looks from first
glance like it would do the trick. Am I on the right track or is there some
other way that is generally used?

TIA,
mick
 
Use the DataContractSerializer class. You'll likely have to do a bit
of attribute markup on your data types, but it works great.
 
Roger Frost said:
Go for it! However I'm a bigger fan of XML Serialization, but to each his
own.

Thanks for that. Got a question about BindingList<> now. How the hell do you find
an item in it?

Assume MyList contains MyItems objects. The MyItem class is defined as -

class MyItem
{
private string name;
private int sumVal;

....getters and setters here
}

Now assume I have the name and I want to find the object with that name in the list-
how do I do that?

myList.Find("Some name") // equiv. of this

Do I have to do a foreach myself for every search?

mick
 
mick said:
Thanks for that. Got a question about BindingList<> now. How the hell do you find
an item in it?

This appears to be a completely different question, having nothing to do
with serialization. If so, IMHO it belongs in a completely new message
topic.

That said…
[...]
Now assume I have the name and I want to find the object with that name in the list-
how do I do that?

myList.Find("Some name") // equiv. of this

Do I have to do a foreach myself for every search?

No, not necessarily. If "MyItem" is a simple container class,
inexpensive to instantiate and implementing IComparable<T>, then you can
using BindingList.IndexOf():

MyItem item = new MyItem("Some name", 5);
int index = myList.Find(item);

The "index" variable gets the index of another MyItem instance in the
list that compares equal to the one you pass in. If it's not found, the
result is -1.

The BindingList class also provides an implementation of IBindingList,
which has a Find() method. It can be a bit awkward to use, but under
the right circumstances it could be appropriate. Assuming your "MyItem"
class has a public Name property:

PropertyDescriptor desc =
TypeDescriptor.GetProperties(typeof(MyItem)).Find("Name", false);

int index = ((IBindingList)myList).Find(desc, "Some name");

The above uses the component model classes to generate a description of
your type and then search for it. Again, -1 is returned if the element
isn't present.

In either case, you can get the actual object in the list just by
accessing it via the returned index.

Finally, you can use the Enumerable extension methods. There are
actually a variety of useful options, depending on your exact needs.
But, here's an example that is reasonably close to the above (again,
assuming there's a "Name" property):

MyItem item = myList
.Cast<MyItem>()
.FirstOrDefault(x => x.Name == "Some name");

Note that because BindingList<T> only implements IEnumerable and not
IEnumerable<T>, you first have to use the Cast<T>() method. Then the
FirstOrDefault() method allows you to provide a predicate delegate to do
the actual comparison on each item. In this case, I used a lambda
expression, but you could use a plain anonymous method:

MyItem item = myList
.Cast<MyItem>()
.FirstOrDefault(delegate(MyItem x)
{
return x.Name == "Some name";
});

Or even a named method:

MyItem item = myList
.Cast<MyItem>()
.FirstOrDefault(CompareName);

where:

bool CompareName(MyItem x)
{
return x.Name == "Some name";
}

Noting, of course, that everywhere I hard-coded "Some name", you can
just as easily use any other expression for comparison.

The FirstOrDefault() method will return the default value for the type
if the item isn't found ("null" for reference types). If you know the
item will be found, or want an exception if it's not, you can just call
First() instead.

Hope that helps.

Pete
 
The next thing Ive learning about is Lists and generic Lists in particular and
one thing I`ve been wondering is how you actually save these lists so that
the contents are available the next time you run the app. Ive had a quick
google and come across Serialization (binary) which looks from first
glance like it would do the trick. Am I on the right track or is there some
other way that is generally used?

The two common serializations are binary and XML.

Binary is faster.

XML is a lot more transparent (imagine that you got saved
an value that crashed the app - with binary it is not easy
to do anything - with XML the file can be edited with any
editor and fixed).

As a rule of thumb I will recommend:
- use binary for non persisted serialization
- use XML for persisted serialization

Save to a file is persistance.

Arne
 
If this is a learning exercise I would defiantly experiment
and become familiar with both.

For saving an application state, "so that the contents
are available the next time you run the app", XML is very
convenient because it is human readable. That doesn't
mean it's better, but it's sure nice while debugging even if
you chose to use binary serialization for the final product.

Do you want your users to be able to edit the saved state
directly? Because with XML they can and will. Binary will
defiantly obfuscate what you have going on to the average
Joe User. Handle incorrect data gracefully, no matter the
method.

XML is great for cross-platform transfer of data because
it's widely supported in many environments. Even if you
can't de-serialize your object directly, you will still be able
to easily and eloquently access it's field's in most cases.
Is this always good thing? Don't ask me, it's your object. :)

I'm getting ahead of myself, if you know you're designing
a cross-platform solution put a little more planning into it
than this. :) But it illustrates a point nonetheless.

There isn't anything overly difficult about either one, so go
for it, learn both, and later you will be happy that you did.
 
If this is a learning exercise I would defiantly experiment
and become familiar with both.

For saving an application state, "so that the contents
are available the next time you run the app", XML is very
convenient because it is human readable. That doesn't
mean it's better, but it's sure nice while debugging even if
you chose to use binary serialization for the final product.

Do you want your users to be able to edit the saved state
directly? Because with XML they can and will. Binary will
defiantly obfuscate what you have going on to the average
Joe User. Handle incorrect data gracefully, no matter the
method.

XML is great for cross-platform transfer of data because
it's widely supported in many environments. Even if you
can't de-serialize your object directly, you will still be able
to easily and eloquently access it's field's in most cases.
Is this always good thing? Don't ask me, it's your object. :)

I'm getting ahead of myself, if you know you're designing
a cross-platform solution put a little more planning into it
than this. :) But it illustrates a point nonetheless.

There isn't anything overly difficult about either one, so go
for it, learn both, and later you will be happy that you did.

Just like to thank you and everyone else for you input and pointing
me in the right direction. It was just an exercise to see how its done.
Usually up to now I`ve been using the Properties to save settings
but I couldnt find how to save Lists. It sounds like I could serialize
all settings instead of using the properties? No? Any reasons I should
continue to use the Properties when possible?

mick
 
Peter Duniho said:
mick said:
Thanks for that. Got a question about BindingList<> now. How the hell do you find
an item in it?

This appears to be a completely different question, having nothing to do
with serialization. If so, IMHO it belongs in a completely new message
topic.

That said…
[...]
Now assume I have the name and I want to find the object with that name in the list-
how do I do that?

myList.Find("Some name") // equiv. of this

Do I have to do a foreach myself for every search?

No, not necessarily. If "MyItem" is a simple container class,
inexpensive to instantiate and implementing IComparable<T>, then you can
using BindingList.IndexOf():

MyItem item = new MyItem("Some name", 5);
int index = myList.Find(item);

The "index" variable gets the index of another MyItem instance in the
list that compares equal to the one you pass in. If it's not found, the
result is -1.

The BindingList class also provides an implementation of IBindingList,
which has a Find() method. It can be a bit awkward to use, but under
the right circumstances it could be appropriate. Assuming your "MyItem"
class has a public Name property:

PropertyDescriptor desc =
TypeDescriptor.GetProperties(typeof(MyItem)).Find("Name", false);

int index = ((IBindingList)myList).Find(desc, "Some name");

The above uses the component model classes to generate a description of
your type and then search for it. Again, -1 is returned if the element
isn't present.

In either case, you can get the actual object in the list just by
accessing it via the returned index.

Finally, you can use the Enumerable extension methods. There are
actually a variety of useful options, depending on your exact needs.
But, here's an example that is reasonably close to the above (again,
assuming there's a "Name" property):

MyItem item = myList
.Cast<MyItem>()
.FirstOrDefault(x => x.Name == "Some name");

Note that because BindingList<T> only implements IEnumerable and not
IEnumerable<T>, you first have to use the Cast<T>() method. Then the
FirstOrDefault() method allows you to provide a predicate delegate to do
the actual comparison on each item. In this case, I used a lambda
expression, but you could use a plain anonymous method:

MyItem item = myList
.Cast<MyItem>()
.FirstOrDefault(delegate(MyItem x)
{
return x.Name == "Some name";
});

Or even a named method:

MyItem item = myList
.Cast<MyItem>()
.FirstOrDefault(CompareName);

where:

bool CompareName(MyItem x)
{
return x.Name == "Some name";
}

Noting, of course, that everywhere I hard-coded "Some name", you can
just as easily use any other expression for comparison.

The FirstOrDefault() method will return the default value for the type
if the item isn't found ("null" for reference types). If you know the
item will be found, or want an exception if it's not, you can just call
First() instead.

Hope that helps.

Pete

Thanks Pete, all good stuff. Not sure how much I`ve taken in:-) but I`ll
experiment with your snippets and see if I can follow what is going on.
Always have to take a few runs at a new wall before I finally break through:-)

mick
 
Oh, well why didn't you say so :)

If you wish to stick with the Properties>Settings, then you might be
able to utilize the Type System.Collections.Specialized.StringCollection.

Someone is going to jump in and say don't do that, but I use it from time
to time as the project allows. It's the only enumerable collection type
allowed in the settings object.

This works great for simple types like string (naturally), int, double, as
well
as enum's. Types that expose a Parse(string) method make it handy to
use.

This is ideal for tracking a list of recently opened files or other
history. But I've used it for more complex things as well.

For example, recently I used this method to keep track of the columns that
the user elects to show in the report. I stored it as the string:

"ColumnName=[true|false]"

Then when the form loads I parse this back out to set my columns' Visible
property.

You can get creative with this, but there will come a point when it just
makes
more sense to abandon Properties>Settings and roll your own mechanism
for saving a state with serialization. So to answer your question yes you
can and you will, once you cross that line of complexity in your
application.
 
Back
Top