object and its type. if the serializable type is generic and it contains bounded types, the metadata about
the generic type contains type information about the bounded types as well. consequently, each
permutation of a generic type with a specific argument type is considered a unique type. for example,
you cannot serialize an object type myclass<int> but deserialize it into an object of type
myclass<string>. serializing an instance of a generic type is no different from serializing a non-generic
type. however, when deserializing that type, you need to declare a variable with matching specific types,
and specify these types again when down casting the object returned from deserialize. code block 11
shows serialization and deserialization of a generic type.
code block 11. client-side serialization of a generic type
[serializable]
public class myclass<t>
{...}
myclass<int> obj1 = new myclass<int>();
iformatter formatter = new binaryformatter();
stream stream = new
filestream("obj.bin",filemode.create,fileaccess.readwrite);
formatter.serialize(stream,obj1);
stream.seek(0,seekorigin.begin);
myclass<int> obj2;
obj2 = (myclass<int>)formatter.deserialize(stream);
stream.close();
when providing custom serialization, you have to add values to a property bag called serializationinfo,
which you also get values from during deserialization. you implement the interface iserializable with
the single method getobjectdata() that provides the serializationinfo used in serialization. you also
must implement a special constructor that accepts the serializationinfo from which to get the object
state.
serializationinfo provides methods for getting or adding field values. each field is identified by a string.
serializationinfo has type-safe methods for most of the clr basic types, such as int and string:
public sealed class serializationinfo
{
public void addvalue(string name, int value);
public int getint32(string name);
//other methods and properties
}
the problem when providing custom serialization on a generic type is that you do not know which of the
adding or getting methods to use. to address this issue, serializationinfo provides methods to add or
get an object and its type:
public void addvalue(string name, object value, type type);
public object getvalue(string name,type type);
note these methods are available in .net 1.1 as well.
when using addvalue(), obtain the type of the generic parameter type. when calling getvalue(), use
a cast to the generic parameter type because getvalue() returns an object. code block 12
demonstrates the use of these addvalue() and getvalue() methods.
code block 12. custom serialization of a generic class
[serializable]
public class myclass<t> : iserializable
{
public myclass()
{}
public void getobjectdata(serializationinfo info,streamingcontext
ctx)
{
info.addvalue("m_t",m_t,typeof(t));
}
private myclass(serializationinfo info,streamingcontext context)
{
m_t = (t)info.getvalue("m_t",typeof(t));
}
t m_t;
}
however, there is a better, safer way for providing custom serialization on a generic type. code block
13 presents the genericserializationinfo utility class that exposes generic addvalue() and
getvalue() methods. by encapsulating a regular serializationinfo, genericserializationinfo
shields the client code from the type retrieval and explicit casting.
code block 13. the genericserializationinfo utility class.
public class genericserializationinfo
{
serializationinfo m_serializationinfo;
public genericserializationinfo(serializationinfo info)
{
m_serializationinfo = info;
}
public void addvalue<t>(string name,t value)
{
m_serializationinfo.addvalue(name,value,value.gettype());
}
public t getvalue<t>(string name)
{
object obj = m_serializationinfo.getvalue(name,typeof(t));
return (t)obj;
}
}
code block 14 shows the same custom serialization code as in code block 12, except it uses
genericserializationinfo. note the use of type inference in the call to addvalue().
code block 14. using genericserializationinfo
[serializable]
public class myclass<t> : iserializable
{
public myclass()
{}
public void getobjectdata(serializationinfo info,streamingcontext
ctx)
{
genericserializationinfo genericinfo = new
genericserializationinfo(info);
genericinfo.addvalue("m_t",m_t); //using type inference
}
private myclass(serializationinfo info,streamingcontext context)
{
genericserializationinfo genericinfo = new
genericserializationinfo(info);
m_t = genericinfo.getvalue<t>("m_t");
}
t m_t;
}
i use genericserializationinfo as a cleaner way of implementing custom serialization, even on