在Suzanne Cook's .NET CLR Notes中,她谈到了“LoadFrom”背景的危险。具体地,
- 如果加载上下文程序集尝试按显示名称加载此程序集,则默认情况下将无法找到它(例如,当mscorlib.dll反序列化此程序集时)
- 更糟糕的是,可以在探测路径上找到具有相同标识但位于不同路径的程序集,从而导致InvalidCastException,MissingMethodException或以后出现意外的方法行为。
如何使用反序列化重现此行为,但是没有显式加载两个不同版本的程序集?
答案 0 :(得分:4)
我创建了一个控制台应用程序A.exe,它间接加载(通过`Assembly.LoadFrom)并从类库中调用(通过反射)代码,B.dll。
Assembly.LoadFrom
使用的位置。<强> A.exe时强>
class Program
{
static void Main(string[] args)
{
// I have a post build step that copies the B.dll to this sub directory.
// but the B.dll also lives in the main directory alongside the exe:
// mkdir LoadFrom
// copy B.dll LoadFrom
//
var loadFromAssembly = Assembly.LoadFrom(@".\LoadFrom\B.dll");
var mySerializableType = loadFromAssembly.GetType("B.MySerializable");
object mySerializableObject = Activator.CreateInstance(mySerializableType);
var copyMeBySerializationMethodInfo = mySerializableType.GetMethod("CopyMeBySerialization");
try
{
copyMeBySerializationMethodInfo.Invoke(mySerializableObject, null);
}
catch (TargetInvocationException tie)
{
Console.WriteLine(tie.InnerException.ToString());
}
Console.ReadKey();
}
}
<强> B.DLL 强>
namespace B
{
[Serializable]
public class MySerializable
{
public MySerializable CopyMeBySerialization()
{
return DeepClone(this);
}
private static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}
}
}
<强>输出强>
System.InvalidCastException:
[A]B.MySerializable cannot be cast to
[B]B.MySerializable.
Type A originates from 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'Default' at location 'c:\Dev\bin\Debug\B.dll'.
Type B originates from 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'LoadFrom' at location 'c:\Dev\bin\Debug\LoadFrom\B.dll'.
at B.MySerializable.DeepClone[T](T obj)
at B.MySerializable.CopyMeBySerialization()
以下是发生的事情:
formatter.Deserialize(ms)
时,它使用存储在MemoryStream中的信息来确定它需要创建的对象类型(以及创建该对象所需的程序集)。 (T)formatter.Deserialize(ms)
中的强制转换失败。附加说明:
Assembly.Load
找到它的地方,那么会有一个InvalidCastException
而不是SerializationException
。 >无法找到程序集&#39; B,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null&#39;。 DeepClone
代码似乎是在对象上进行深度克隆的更流行的方法之一。请参阅:Deep cloning objects in C#。因此,从任何加载到&#34; LoadFrom&#34;上下文,你不能成功使用反序列化(没有跳过额外的箍以允许程序集成功加载默认的&#34;加载&#34;上下文)。