c# - 使用动态加载的 .Net 程序集进行二进制序列化

标签 c# .net serialization .net-assembly

我将我的类的一个实例序列化到一个文件中(使用 BinaryFormatter)

之后,在另一个项目中,我想反序列化这个文件,但是没有成功,因为我的新项目没有我的旧类的描述。 .Deserialize() 发生异常

Unable to find assembly '*MyAssembly, Version=1.9.0.0, Culture=neutral, PublicKeyToken=null'.*".

但我有程序集的 .DLL,其中包含我要反序列化的旧类的描述。

我不想在项目中添加此 DLL 的引用(我希望能够反序列化任何类型的程序集的类...)

如何通知序列化器/反序列化器使用我动态加载的程序集?

最佳答案

假设您正在通过 Assembly.Load() 加载程序集或 Assembly.LoadFrom() ,然后如 this answer 中所述给 SerializationException for dynamically loaded Type 来自 Chris Shain , 您可以使用 AppDomain.AssemblyResolve 在反序列化期间加载动态程序集的事件。但是,出于安全原因,您将希望防止加载完全意外的程序集。

一种可能的实现方式是引入以下内容:

public class AssemblyResolver
{
    readonly string assemblyFullPath;
    readonly AssemblyName assemblyName;

    public AssemblyResolver(string assemblyName, string assemblyFullPath)
    {
        // You might want to validate here that assemblyPath really is an absolute not relative path.
        // See e.g. https://stackoverflow.com/questions/5565029/check-if-full-path-given
        this.assemblyFullPath = assemblyFullPath;
        this.assemblyName = new AssemblyName(assemblyName);
    }

    public ResolveEventHandler AssemblyResolve
    {
        get
        {
            return (o, a) =>
                {
                    var name = new AssemblyName(a.Name);
                    if (name.Name == assemblyName.Name) // Check only the name if you want to ignore version.  Otherwise you can just check string equality.
                        return Assembly.LoadFrom(assemblyFullPath);
                    return null;
                };
        }
    }
}

然后,在启动的某个地方,添加一个合适的 ResolveEventHandlerAppDomain.CurrentDomain.AssemblyResolve例如如下:

class Program
{
    const string assemblyFullPath = @"C:\Full-path-to-my-assembly\MyAssembly.dll";
    const string assemblyName = @"MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";

    static Program()
    {
        AppDomain.CurrentDomain.AssemblyResolve += new AssemblyResolver(assemblyName, assemblyFullPath).AssemblyResolve;
    }

ResolveEventHandler 检查请求的程序集是否具有您的动态程序集的名称,如果有,则从预期的完整路径加载当前版本。

另一种方法是编写自定义 SerializationBinder 并将其附加到 BinaryFormatter.Binder .在 BindToType (string assemblyName, string typeName) Binder 需要检查属于您的动态程序集的类型,并适本地绑定(bind)到它们。这里的技巧是处理动态加载的类型嵌套在另一个程序集中的泛型中的情况,例如一个List<MyClass> .在那种情况下 assemblyName将是 List<T> 的程序集名称不是 MyClass .有关如何执行此操作的详细信息,请参阅

comments @sgnsajgon问,我想知道为什么我不能像在项目中显式引用签名程序集时那样反序列化流 - 只是 formatter.Deserialize(stream)没有别的。

虽然我不知道 Microsoft 员工在设计这些类时是怎么想的(回到 .Net 1.1 ),但可能是因为:

顺便说一句, What are the deficiencies of the built-in BinaryFormatter based .Net serialization? 对使用 BinaryFormatter 时可能遇到的其他问题进行了有用的概述。 .

关于c# - 使用动态加载的 .Net 程序集进行二进制序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18881659/

相关文章:

c# - 如何清空 EntityFramework DbContext?

C# 如何使用存储在构造函数变量中的类名创建新对象?

java - 为什么生成 long serialVersionUID 而不是简单的 1L?

c# - 更新linq中的单行

c# - 在 C# 中加入/合并数组

c# - 读取 XML 数据并构建查询以将值插入 SQL Server 数据库的最佳方法是什么?

java - 在 main 上序列化泛型类型

c# - 生成时间表 - 需要好的算法

c# - 我发现部分方法非常有用,但没有部分属性。他们没有被包括在内有充分的理由吗?我有什么选择?

serialization - 处理 Hadoop SequenceFile 中的 Writables 完全限定名称更改