TheSwamp
Code Red => .NET => Topic started by: Glenn R on November 29, 2006, 06:47:18 PM
-
I had some time and wanted to deepen my understanding of some .NET topics, so I decided to look at generics. After reading up on these a bit more, you just gotta love them. In .NET 1.X, if you wanted to create a collection class, most people, including myself, derived a new class from the abstract base class CollectionBase.
This internally implements an ArrayList as a protected member, so your derived class could access it, but object users could not; however, I digress.
You then had to provide implementations for a dozen or so methods. Doesn't sound too bad....untill you need to contain some other type of object...stir well and repeat....and repeat. Gets very tedious after a while.
Along comes Generics and all this goes out the door. Here's an example:
[Serializable]
public class Cars : Collection<Car>
{
Car _currentCar;
public Car CurrentCar
{
get { return _currentCar; }
set { _currentCar = value; }
}
public Car this[string name]
{
get
{
foreach (Car c in Items)
if (c.Name == name)
return c;
return null;
}
set
{
foreach (Car c in this)
if (c.Name == name)
{
this.Items[this.Items.IndexOf(c)] = value;
return;
}
}
}
}
[Serializable]
public class Car
{
/* Needed for xml serialization, but not for binary
private Car( ) { }
*/
public Car(string name, int currentSpeed)
{
this.name = name;
this.currentSpeed = currentSpeed;
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private int currentSpeed;
public int CurrentSpeed
{
get { return currentSpeed; }
set { currentSpeed = value; }
}
}
First, we have a collection class that contains cars for want of a better example. You can see that is has a public property to return the current car and a custom indexer that uses a string as the key (the car's name). If you didn't want to maintain what the 'current' car is or be able to index via a string, then you could reduce the class to just this:
public class Cars : Collection<Car> { }
This class is extending CollectionBase's .NET 2.0 generic counterpart, Collection<T> which is in System.Collections.ObjectModel.
As a futher example, say you wanted to serialize and deserialize to binary, a collection of cars.
You would do so thusly:
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace Ser
{
public class Test
{
static void Main( )
{
Cars cars = new Cars();
// Get my car...
Car gCar = new Car("G", 110);
cars.Add(gCar);
//...and wifey's...
Car jCar = new Car("J", 90);
cars.Add(jCar);
// Let the cat loose...
Car sootysCar = new Car("Sooty", 150);
cars.Add(sootysCar);
// Give the doggy a go as well...
Car maxsCar = new Car("Max", 130);
cars.Add(maxsCar);
// Set the current car...
cars.CurrentCar = sootysCar;
// Save the cars out...
Serialize(cars);
// Wipe 'em out
cars = null;
// Read 'em back in...
cars = Deserialize();
// Display some interesting stats about the cars...
if (cars != null)
DumpCars(cars);
// Exercise an indexer...
Car anotherCar = cars["G"];
Console.WriteLine("Another car: {0}", anotherCar.Name);
//...and the other indexer...
Car yetAnotherCar = cars[1];
Console.WriteLine("Yet Another car: {0}", yetAnotherCar.Name);
}
private static void DumpCars(Cars cars)
{
foreach (Car c in cars)
Console.WriteLine("{0}'s car is travelling at {1}kph...", c.Name, c.CurrentSpeed);
Console.WriteLine("Current car, {0}, is travelling at {1}kph...",
cars.CurrentCar.Name, cars.CurrentCar.CurrentSpeed);
}
static void Serialize(Cars cars)
{
FileStream fs = new FileStream("CarsDataFile.dat", FileMode.Create);
BinaryFormatter bf = new BinaryFormatter();
try
{
bf.Serialize(fs, cars);
}
catch (SerializationException sex)
{
Console.WriteLine("Serialization failed: {0}", sex.Message);
throw;
}
finally
{
fs.Close();
}
}
static Cars Deserialize( )
{
Cars reconstitutedCars = null;
FileStream fs = new FileStream("CarsDataFile.dat", FileMode.Open);
try
{
BinaryFormatter bf = new BinaryFormatter();
reconstitutedCars = (Cars)bf.Deserialize(fs);
return reconstitutedCars;
}
catch (SerializationException sex)
{
Console.WriteLine("Deserialization failed: {0}", sex.Message);
throw;
}
finally
{
fs.Close();
}
}
}
}
Comments anyone?
Cheers,
Glenn.
-
You expected no-one to catch this ... ?
catch (SerializationException sex)
excuse the pun :-)
-
catch (SerializationException sex)
It is a sublime subliminal message hidden in there......
-
Caught by the one I knew would catch it first, hey Kerry ;)
-
Just a couple of notes
Anyone putting this together will need the statement
using System.Collections.ObjectModel;
otherwise the Collection will not be recognised.
Serializing the object has some real potential, [once I can understand it :-) ]
Extra reading :
http://download.microsoft.com/download/c/b/f/cbfbdf30-de37-45a7-a806-20a93f94b7b8/Michaelis_ch11.pdf
-
From my original post Kerry:
This class is extending CollectionBase's .NET 2.0 generic counterpart, Collection<T> which is in System.Collections.ObjectModel.
Yeah binary serialization will take private as well as public, whereas XML serialization will only take public and it it's a collection class will only take the collection - nothing else.
Good fun eh Kerry? :D
Cheers,
Glenn.
-
DUH !! I'm blind as well as Stupid .... sorry ..
-
Anyone testing may want to add something like
Console.ReadKey();
to the bottom of the DumpCars() method
so that the Command dialog stays open till a key is hit ...
///---- added
or something like this in Main ....
if (cars != null)
DumpCars(cars);
Console.ReadKey(); // <-- kwb
// Exercise an indexer...
Car anotherCar = cars["G"];
Console.WriteLine("Another car: {0}", anotherCar.Name);
Console.ReadKey(); // <-- kwb
//...and the other indexer...
Car yetAnotherCar = cars[1];
Console.WriteLine("Yet Another car: {0}", yetAnotherCar.Name);
Console.ReadKey(); // <-- kwb
}
///---------
Nice Stuff Glenn
hehehehe
is Sooty related to Brock ??
-
Thanks Kerry. No Sooty isn't related to Brock - she's our dog's worst nightmare :) She actually got him to roll over the other night - honest :-D
I usually add Console.Readline(); at the end but I must have left it off.
If you want to keep the console window open when the run is finished and you're not debugging:
Debug->Start Without Debugging or Ctrl+F5 will do the same.
I'm going to have to get around to retro-fitting a few classes that I use. The binary serialization is really appealing to me at the moment - also keeps prying little mitts out of the data file, instead of it being a free for all xml.
-
Thanks Glenn,
I just now had time to digest this. Very handy!
Now, I've got to go back and redesign my collection classes created the last few months....