Groups | Blog | Home
all groups > c# > march 2006 >

c# : Does serialization/deserialization compress my array?


Marcus
3/7/2006 11:44:23 PM
I have a couple of classes looking like this:
========================================

[Serializable]
public class AdminSettingsData
{
public string adminSettingsPath;
public string adminSettingsFile;
public string usersSettingsPath;

public bool playersHaveToLogin;

private TBusers[] users = new TBusers[100];
private int userCount;

public TBusers[] Users
{
get { return users; }
set { users = value; }
}

public int UserCount
{
get {return userCount; }
set {userCount = value; }
}
}

[Serializable]
public class TBusers
{
public string name;
public string passwd;
}

In the constructor I do:
=====================

// this variable is passed to other forms in the app for
// letting the administrator add
// or remove entries of users
adminData = new AdminSettingsData();

for (int i = 0; i < 100; i++)
{
adminData.Users[i] = new TBusers();
}

I then initializes some name and passwords in TBusers and Serializes
this with binaryFormatter to a file.
When I later on Deserializes this file by the line:
adminData = (AdminSettingsData)formatter.Deserialize(fs);

I get the names and passwords from the file (I have only initialized 4
of them ([0]-[3]).
The problem is that after Deserialization when I want to add one more
name and password to adminData.Users[4] then multiple entries (like
adminData.Users[5] and adminData.Users[6]) are also filled with that
name and password and likewise when I try nullify the entries 5 and 6,
I also gets entry 4 nullified. It is like multiple entries in my array
are referencing the same memory.

If I initialize the entry adminData.Users[4] with name and password
before the Deserialization then it behaves like expected (only
adminData.Users[4] is touched).


Question 1:
===========
shouldn't
private TBusers[] users = new TBusers[100];
be enough to allocate my array. Why is the loop necessary?
for (int i = 0; i < 100; i++)
{
adminData.Users[i] = new TBusers();
}


Question 2:
============
Is it the binaryFormatter that compresses all the tailing null entries
in adminData.Users array or what is happening here?


I am new to c#. Any help would be greatly appreciated!
Marc Gravell
3/8/2006 12:00:00 AM
A1: without the loop, they will all initialise to their default value, which
is null - so you won't actually have *any* users - just an array 100 nulls.
If coded correctly then this woulod be fine - you need to avoid anything
that does something like theArray[index].Property = value (without testing),
as it will throw an exception because of the null.

A2: it shouldn't do; you haven't shown any serialization code, so hard to
tell what is going wrong

Observation: with the count properties etc, it *suggests* that the set of
users is variable over time; perhaps an ArrayList (1.1) or List<TBUsers>
would be a better store? This would also save you having to create empty
users at the outset.

Minor note: TBUsers is confusingly named - it sounds like a container, but
is, in fact, a single entity; also the T suggests template (although it
might be a reasonable abbreviation in this case) - suggest TBUser would be
less confusing?

[quoted text, click to view]

Helge Jensen
3/8/2006 12:00:00 AM


[quoted text, click to view]

What about just:

protected IList<TBusers> users;

or

protected IList users;

in C#1, or even just dropping the protection, since you provide public
set methods anyway:

public readonly IList Users;

[quoted text, click to view]

Why are you providing get/set methods to your private data? you might as
well declare it public instead.

[quoted text, click to view]

Same here, why provide access to that? with the code i propose users can
say:

TBusers users = ...;
users.Count;

users

[quoted text, click to view]

A better name would be User, we are defining properties for each user here.

[quoted text, click to view]

how about just storing your users in a .NET2 ICollection:

public class AdminSettings {
...
ICollection<User> Users = new List<User>();
}

[quoted text, click to view]

Why doesn't the AdminSettingsData.AdminSettingsData initialize it's
Users property itself, or accept it as an argument?

[quoted text, click to view]

That's wierd, how does your "nullify" code look?

[quoted text, click to view]

The loop fills Users, with actual TBusers instances, not null. why would
you want to do that?

[quoted text, click to view]

There are no null-entries. You just initialized each entry to a new TBusers

[quoted text, click to view]

Perhaps take a course on object-oriented programming?

--
Helge Jensen
mailto:helge.jensen@slog.dk
sip:helge.jensen@slog.dk
Marcus
3/8/2006 4:31:01 AM
[quoted text, click to view]

I am providing get/set methods because I am planning that I will
eventually check data for constraints and other abuse within these
get/set methods.

[quoted text, click to view]

It could do that, yes. Maybe I will eventually. My app is not 100%
ready yet (or not even near) so there is still time. Right now
AdminSettingsData is just a container class for data without any
methods of its own.

[quoted text, click to view]

Yes I will change this!

[quoted text, click to view]

To avoid exceptions when my program tries to access a field in a null
object.

[quoted text, click to view]

OK, what I meant was the entries that contains objects which
datamembers are null.


[quoted text, click to view]

Thanks for the help.
Could work a bit on that attitude though...
Marcus
3/8/2006 4:34:08 AM
thanks for the help. I will examine my code further. Maybe I will post
my serialize/deserialize code. Or maybe I try implement my
saving/loading via some mechanism other than serialization.
Marcus
3/8/2006 5:32:48 AM
OK, that helped alot!!

I will try these approaches as soon as I can.

Thanks!
Helge Jensen
3/8/2006 2:22:16 PM
[quoted text, click to view]

Let me address that first.

I'm sorry if I came over offensive, thats not intended.

The external initialization of internal data and the non-use of the .NET
provided resizing collections for data-storage made me think that
perhaps some general OO knowledge would help.

[quoted text, click to view]

You can postpose making get/set untill then. I've found that designing
for the future is usually best done as late a possible.

[quoted text, click to view]

The corner-stone of object oriented programming is the idea that data
and the functions operating on the data should be grouped together in an
object modelling the data and it's interaction with the surroundings.
Initializing the data inside the constructor would be just as easy, and
would leave any constructed object in a well-defined valid state.

Wouldn't the simplest solution be to just have the users as:

[Serializable]
public class User {
public string Name;
public string Password;
public User(string name, string password)
{ this.Name = name; this.Password = password; }
}
[Serializable]
public class AdminSettingsData {
public ICollection<User> Users = new List<User>();
}

Now you can add users by doing:

ICollection<User> users = adminSettings.Users;
users.Add(new User("name", "password"));

and then later write another implementation of the userlist to verify
any constraints on the list of users.

[quoted text, click to view]

That exception would expose a programming-error -- which would go
unnoticed if you filled the array with default-initialized Users.

[quoted text, click to view]

OK. I usually prefer to let classes whose instances require
initialization to have a valid state accept that state in the
constructor. Like in the above class User. That way there is never any
objects not in a valid state.

--
Helge Jensen
mailto:helge.jensen@slog.dk
sip:helge.jensen@slog.dk
AddThis Social Bookmark Button