The problem
An object (with a private MethodInfo
field) serialized with version 1.0 of an assembly won't be deserialized with the version 1.1 of that assembly (a SerializationException
will be thrown because required method has not been found).
What's changed?
I found that in .NET 4.5 the serialization mechanism of a MemberInfo
via MemberInfoSerializationHolder
has been changed. In the past (up to .NET 4.0) the serialized data was the method signature (obtained with a simple MethodInfo.ToString()
).
According to comments in the .NET source code they added a second signature obtained via SerializationToString()
because:
m_signature stores the ToString() representation of the member which is sometimes ambiguous. Mulitple overloads of the same methods or properties can identical ToString(). m_signature2 stores the SerializationToString() representation which should be unique for each member. It is only written and used by post 4.0 CLR versions.
For what I can see the MemberInfoSerializationHolder.GetRealObject()
uses this (simplified) code to resolve the method (from .NET source code):
for (int i = 0; i < methods.Length; i++)
{
if (m_signature2 != null) // SerializationToString() signature
{
if (((RuntimeMethodInfo)methods[i]).SerializationToString().Equals(m_signature2))
{
methodInfo = methods[i];
break;
}
}
else
{
if (methods[i].ToString().Equals(m_signature))
{
methodInfo = methods[i];
break;
}
}
}
if (methodInfo == null)
throw new SerializationException(...);
In this case the deserialization fails because the m_signature2
signature can't be found because assembly name contains version information then String.Equals()
won't match MyAssembly, Version=1.0.0.0
with MyAssembly, Version=1.1.0.0
and an exception will be thrown.
The question
I would expect the Framework will fail back to old search method if the new search fails (at least because of compatibility with existing code). I don't understand why this comparison is made with a String.Equals()
, after all the version of an assembly is resolved at run-time (and newer version will be loaded by default), I agree it can't resolve the assembly version there but it may remove/ignore it if the strict search fails.
I know it's terrible to serialize a MethodInfo
but at this moment this fix may involve too many changes (both in architecture and code) and no one would start this refactoring in that old code (moreover binary compatibility for archives must be kept for both old and new versions, in both directions).
So far I didn't try but is this issue applicable to delegates too? Is there any solution (with attributes or with small code changes) to workaround this problem?