Does serialization/deserialization compress my array?

M

Marcus

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 = 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 = 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!
 
M

Marc Gravell

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?

Marcus said:
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 = 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 = 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!
 
H

Helge Jensen

Marcus said:
private TBusers[] users = new TBusers[100];

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;
public TBusers[] Users
{
get { return users; }
set { users = value; }
}

Why are you providing get/set methods to your private data? you might as
well declare it public instead.
public int UserCount
{
get {return userCount; }
set {userCount = value; }
}

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

TBusers users = ...;
users.Count;

users
[Serializable]
public class TBusers

A better name would be User, we are defining properties for each user here.
{
public string name;
public string passwd;
}

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

public class AdminSettings {
...
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 = new TBusers();
}


Why doesn't the AdminSettingsData.AdminSettingsData initialize it's
Users property itself, or accept it as an argument?
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.

That's wierd, how does your "nullify" code look?
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 = new TBusers();
}


The loop fills Users, with actual TBusers instances, not null. why would
you want to do that?
Question 2:
============
Is it the binaryFormatter that compresses all the tailing null entries
in adminData.Users array or what is happening here?

There are no null-entries. You just initialized each entry to a new TBusers
I am new to c#. Any help would be greatly appreciated!

Perhaps take a course on object-oriented programming?
 
M

Marcus

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

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.
Why doesn't the AdminSettingsData.AdminSettingsData initialize it's
Users property itself, or accept it as an argument?

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.
A better name would be User, we are defining properties for each user here.

Yes I will change this!
The loop fills Users, with actual TBusers instances, not null. why would
you want to do that?

To avoid exceptions when my program tries to access a field in a null
object.
There are no null-entries. You just initialized each entry to a new TBusers

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

Perhaps take a course on object-oriented programming?

Thanks for the help.
Could work a bit on that attitude though...
 
M

Marcus

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.
 
H

Helge Jensen

Marcus said:
Thanks for the help.
Could work a bit on that attitude though...

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.
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.

You can postpose making get/set untill then. I've found that designing
for the future is usually best done as late a possible.
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.

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.
To avoid exceptions when my program tries to access a field in a null
object.

That exception would expose a programming-error -- which would go
unnoticed if you filled the array with default-initialized Users.
OK, what I meant was the entries that contains objects which
datamembers are null.

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top