| Servergeek |
| Mickey Williams' weblog |
|
My C# BookMicrosoft Press PageOn Amazon Racing LinksSlalomSkateboarder.comNCDSA slalom page 3dm Ick Sticks Pocket Pistols .NETScott GuthrieRob Howard .NET Notes BradA LonghornScobleChris Sells ServicesDon BoxChristian Weyer All Things Distributed Ingo Rammer Tim Ewald BlawgsBag and BaggageSCOTUS Blog EconArg MaxCapital Spectator OtherWilliam Gibson |
Saturday, May 10, 2003
Generic Serialization with C#Posted 3:55 PMIt's been a busy week, and I'm still spending cycles here and there on the generic collections. During the week, I was asked for an exemplar for serialization to/from byte arrays. If you're interested, the basic serialization code to and from a stream looks something like (to/from FileStream instances):
Person p = new Person();
p.Name = "Mickey";
p.Age = 412;
using(FileStream fs = new FileStream("person.bin", FileMode.Create))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(fs, p);
}
using(FileStream fs = new FileStream("person.bin", FileMode.Open))
{
BinaryFormatter bf = new BinaryFormatter();
Person p2 = (Person)bf.Deserialize(fs);
Console.WriteLine("Person: Name = {0}, Age = {1}", p2.Name, p2.Age);
}
Code like this doesn't generally require you to worry too much about type safety. The formatter is happy to work with any object graph you hand to it. However, another application for serialization is to freeze-dry an object to bytes, then re-hydrate it later. In such a case, you might wrap the serialization code in type-safe wrappers like this:
// object to byte array:
public byte[] MyObjToBlob(MyObj obj)
{
byte[] blob = null;
using(MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, obj);
ms.Flush();
blob = ms.ToArray();
}
return blob;
}
// Byte array to object:
public MyObj BlobToMyObj(byte[] blob)
{
MyObj result = null;
using(MemoryStream ms = new MemoryStream(blob))
{
BinaryFormatter bf = new BinaryFormatter();
result = (MyObj)bf.Deserialize(ms);
}
return result;
}
Of course, the problem with code like this is that you need to duplicate these methods every time you have a new type that you want to serialize in a strongly-typed manner. Since I've been writing some generic C# code with Gyro, I decided to translate these two methods into generic equivalents:
byte[] Serialize<T>(T obj)
{
byte[] blob = null;
using(MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, obj);
ms.Flush();
blob = ms.ToArray();
}
return blob;
}
T Deserialize<T>(byte[] blob)
{
T result;
using(MemoryStream ms = new MemoryStream(blob))
{
BinaryFormatter bf = new BinaryFormatter();
result = (T)bf.Deserialize(ms);
}
return result;
}
The generic methods would be used like this:
Person p = new Person();
p.Name = "Mickey";
p.Age = 42;
...
byte [] bits = Serialize<Person>(p);
Person px = Deserialize<Person>(bits);
Console.WriteLine("Person: Name = {0}, Age = {1}", px.Name, px.Age);
Or, if we create a new BinaryFormatter<T>, we can greatly simplify serialization and eliminate a lot of extra syntax. We can just subclass BinaryFormatter, and ... ooops - it's sealed. But we have the source! But a quick survey indicates that I'd also need to genericize ObjectReader and ObjectWriter, so the perfect solution (for this narrow case) will need to wait for another day.
using(MemoryStream ms = new MemoryStream())
{
BinaryFormatter<MyObj> bf = new BinaryFormatter<MyObj>();
bf.Serialize(ms, obj);
ms.Flush();
blob = ms.ToArray();
}
...
using(MemoryStream ms = new MemoryStream(blob))
{
BinaryFormatter<MyObj> bf = new BinaryFormatter<MyObj>();
MyObj obj = bf.Deserialize(ms);
}
It would be nice to get some compile-time support to ensure that the actual T passed to me is serialization-compatible. I can enforce support for ISerializable like this:
byte[] Serialize<T> where T: ISerializable (T obj)
{
...
}
But of course this leaves out types tagged with [Serializable], even though this is the most common serialization use case. Too bad there's no way request compile-time checking for attribute metadata. I've got no clue what the syntax would be, and there are perfectly reasonale reasons why I can't get it, but it would be nice to have something like: byte[] Serialize<T> where T: [Serializable] (T obj) ... In the interests of completeness, obvious arguments against metadata constraints are:
Wednesday, May 07, 2003
Copyright MythsPosted 5:15 PMGreat (and funny) article on copyright myths from Jonathan Pink. [via Bag and Baggage] Monday, May 05, 2003
Using Gyro Generics with C#Posted 12:49 PMSo the journey begins...
/*
Servergeek C# Generic Library
...
*/
struct Pair<F,S>
{
F _first;
S _second;
public Pair(F first, S second)
{
_first = first;
_second = second;
}
public F First
{
get { return _first; }
}
.
.
.
}
The container examples that come with Gyro were a good starting point - I should have rough cuts of the basic container types by the weekend. Goals for the first cut are containers that are approximately compatible with the current non-generic BCL types, simplifying the replacement of types such as StringCollection with ContainerOfYourChoice<string>. Caveat: I'm sure that these types won't directly map into whatever's coming in Whidbey, so this is strictly a get-some-experience-with-generics in .NET thang.
|