.NET Runtime Serialization
Could someone please explain what's the difference between inheriting from ISerializable
interface and declaring your object as [Serializable]
?
I know that in the first case you are have to implement the ISerializable
interface members, while in the second case this work is likely to be done by the C# itself.
But what doesn't make sense to me then is the following behavior:
public void Foo<T>() where T : ISerializable
{
// Whatever
}
Now, if I have some class like this:
[Serializable]
public class Value
{
public String Value { get; set; }
}
And unfortunately I can't call my X.Foo<Value>()
, because the compiler says:
There is no implicit reference conversion from 'Value' to 'System.Runtime.Serialization.ISerializable'
I'm pretty sure it's my misunderstanding of something obvious, so please point out what am I doing wrong.
UPDATE (IMPORTANT :)
How do I make the where T : ISerializable
statement开发者_JAVA百科 work with [Serializable]
class too? Is there a way?
What I'm trying to achieve is the compilation-time error if the supplied type T
is not serializable (by using [Serializable]
or ISerializable
way).
Obviously, my current check handles only the second case, so how do I make it handle both of them?
Serializable
is merely an attribute you place on a class to let classes such as SoapFormatter
know (via reflection) it can be serialized. Decorating a class with an attribute does not make a class implement an interface, which is why the compiler complains in your case. If memory serves, one implements ISerializable
if one wants more control over the serialization process.
To answer your update: there is no way you can put a generic constraint on the presence of an attribute.
The next best thing you can do is throw an exception (obviously at runtime, not at compile-time). For a generic method, it would look something like this:
public void Foo<T>()
{
if (!typeof (ISerializable).IsAssignableFrom(typeof (T))
|| !typeof (T).GetCustomAttributes(true).OfType<SerializableAttribute>().Any())
{
throw new InvalidOperationException(string.Format("Type {0} is not serializable.", typeof (T).FullName));
}
}
For a generic class, you could do this in the static constructor (fails faster):
public class Foo<T>
{
static Foo()
{
if (!typeof(ISerializable).IsAssignableFrom(typeof(T))
|| !typeof(T).GetCustomAttributes(true).OfType<SerializableAttribute>().Any())
{
throw new InvalidOperationException(string.Format("Type {0} is not serializable.", typeof(T).FullName));
}
}
}
[Serializable]
is just an attribute. It doesn't make your class implement the ISerializable interface. All it does it indicate to the .NET framework that your class can be serialized.
So when you attempt to serialize your class, the framework will check how it should do so. If there is no ISerializable interface, it will attempt to use the built-in serializers and take care of it for you. If you explicitly implemented ISerializable, then it'll use your custom serialization implementation.
This is why sometimes you have to write classes like
[Serializable]
public class MyClass : ISerializable
{}
Unfortunately you cannot do what you want and achieve compile-time checking for either [Serializable]
or ISerializable
. The best you can do is a run-time check inside the method whether the type passed in is serializable or not (either through reflection or by catching a serialization exception).
Alternatively, you could adopt a convention that all your serializable types must implement your own version of ISerializable:
public interface ICanBeSerialized
{
// this interface is left intentionally blank
}
public class Value : ICanBeSerialized
{
// do whatever
}
public class MyClass
{
public void Foo<T>() where T : ICanBeSerialized
{ }
}
The attribute simple indicates that the class can be serialized. Implementing ISerailizable will override the serialization process. You class Value should implement the ISerializable interface.
public class Value : ISerializable
{
public String Value { get; set; }
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
}
}
ISerializeable
enables an object to create its own (de)serialization. You can use this to serialize deep data structures to a flattened version and recreate it when deserializing or when wanting to serialize specific structures to simple values (like Color
).
In general, the inbuilt serialization process is sufficient, though.
精彩评论