替换仅通过反射加载的程序集

本文关键字:加载 程序集 反射 替换 | 更新日期: 2023-09-27 18:00:20

在我目前正在处理的项目中,我们有许多类仅通过反射实例化,它们所属的程序集不被任何其他类引用。

此方案允许在运行时替换程序集,以扩展/更正前一个程序集的功能。请注意,在我们的特定情况下,不可能使用MarshalByRefObject,因此,同一程序集的不同版本(公开具有相同名称但不同功能的类)最终会加载在同一AppDomain中。

我给出了一个极其简化的例子:考虑以下接口声明和控制台应用程序

public interface ISomeInterface
{
    string getData();
}
class Program
{
    static void Main(string[] args)
    {
        byte[] lastLibrary = null;
        Assembly lastAssembly = null;
        while (true)
        {
            byte[] theLibrary = File.ReadAllBytes("ClassLibrary1.dll");
            if (lastLibrary == null || !theLibrary.SequenceEqual(lastLibrary))
            {
                lastAssembly = Assembly.Load(theLibrary);
            }
            ISomeInterface obj = lastAssembly.CreateInstance("ClassLibrary1.Class1") as ISomeInterface;
            Console.WriteLine(obj.getData());
            lastLibrary = theLibrary;
            Thread.Sleep(1000);
        }
    }
}

以及以下接口实现(在单独的组件上):

public class Class1 : ISomeInterface
{
    public string getData()
    {
        return "someText";
    }
}

正如预期的那样,如果我更改ISomeInterface的实现(例如,将"someText"更改为"someOtherText"),并用新的dll替换旧的dll,则使用最新的版本。不过,我想知道:这种机制对软件的稳定性造成问题的可能性有多大?我的意思是,在我只通过反射实例化这些类而没有其他组件引用它们之前,一切都安全吗?至于我们的初步测试,看起来一切都很好,但我也想听听专家的意见。

我知道在这个特定的例子中,可以使用MarshalByRefObject来完成所有事情,但正如我之前所说,我们不可能朝着这个方向前进。

替换仅通过反射加载的程序集

这样的事情应该可以正常工作,但我认为你误解了实际发生的事情。

当您将程序集加载到AppDomain中时,只要AppDomin存在,它就不会被释放。您要做的是加载一个新部件。但这样做,就不是发布旧版本。例如,如果以前版本的对象仍然存在,它将返回"someText",即使新创建的对象将返回"someOtherText"。虽然这两个对象的类型名称都是ClassLibrary1.Class1,但它们是不同的类型。

如果这种行为对你来说是正确的,那么你应该没事。但不要忘记,所有的旧版本仍然被加载并保存在内存中,所以这样做实际上会导致内存泄漏。