微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何从 AppDomain 实例化 IModule 继承类?

如何解决如何从 AppDomain 实例化 IModule 继承类?

在这里有点困惑,没有从谷歌那里得到太多帮助。这是我想要做的:

public Boolean LoadModule(String moduleHandle)//name of module MUST match its .dll name. Name of AppDomain is the same as the Handle.
    {
        try
        {
            AppDomain moduleDomain = AppDomain.CreateDomain(moduleHandle);
            String pathToDll = @"C:\IModules.dll"; //Full path to dll you want to load
            Type moduleType = typeof(IModule);
            IModule loadedModule = (IModule)moduleDomain.CreateInstanceFromAndUnwrap(pathToDll,moduleType.FullName);

            ModuleList.Add(loadedModule,moduleDomain);
            broadcast("Module loaded: " + moduleHandle,ModuleManagerHandle);
            return true;
        }
        catch (Exception e)
        {
            //console writeline the error? probably cant
            OutputBox.AppendText(e.ToString() + Environment.NewLine);
            return false;
        }
    }

我以为我终于弄明白了,但是当我尝试实例化 IModule(在本例中为 ConsoleModule)时,出现以下错误: System.MissingMethodException: 未找到类型“IModules.IModule”的构造函数

我认为这意味着我需要一个构造函数,就好像这是一个在此函数调用中实例化自身的类对象,但我不能让接口具有构造函数。 我已经看到其他线程提出了解决这个问题的方法,但他们使用程序集而不是 appdomain,这会破坏卸载模块的能力。我担心如果没有卸载模块的能力,应用程序会随着时间的推移而遭受内存膨胀。

最终目标是能够编写一个模块,让程序运行并在运行时加载/卸载模块,而无需对核心程序进行任何更改,并随时随地添加功能。 任何人都知道解决方法或处理动态模块加载和卸载的更好方法

解决方法

这是在 .NET 5.0 AssemblyLoadContext 中修复的:

var basePath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
            AssemblyLoadContext moduleAssemblyLoadContext = new AssemblyLoadContext(moduleHandle,true);
            Assembly moduleAssembly = moduleAssemblyLoadContext.LoadFromAssemblyPath($"{basePath}\\{moduleHandle}.dll");

            Type[] types = moduleAssembly.GetTypes();
            foreach (Type type in types)
            {
                // Does this class support the transport interface?
                Type typeModule = type.GetInterface("IModule");
                if (typeModule == null)
                {
                    // Not supported.
                    continue;
                }

                // This class supports the interface. Instantiate it.
                IModule loadedModule = moduleAssembly.CreateInstance(type.FullName) as IModule;
                if (loadedModule != null)
                {
                    loadedModule.LoadedModule(this);
                    ModuleList.Add(loadedModule,moduleAssemblyLoadContext);
                    Broadcast("Module loaded: " + moduleHandle,ModuleManagerHandle);
                    OutputTextBox.AppendText(moduleHandle + " was loaded." + Environment.NewLine);
                    // Successfully created the interface. We are done.
                    return true;
                }
            }
            return false;

无法再找到源代码,但发现它正在寻找相关问题(无论如何您都可以在 MSDN 上找到它)。这成功地将程序集加载和卸载到它们的上下文中。用户必须将 isCollectible 值设置为 TRUE 才能启用完全卸载。

我遇到的唯一问题是 .NET 5.0 与自身不兼容,但在尝试加载程序集时,作为 .NET 5.0 加载到 .NET 5.0 程序中的库会给出 BadImageFormatException。要修复,请将 LIBRARY 设置为下一个最新的目标框架(在我的例子中是 .NET Core 3.1)并将新编译的 dll 移动到它所到的任何位置,应用程序应该使用新的 dll 运行。

,

错误告诉您没有找到类型 IModule 的默认(空)构造函数。由于 IModule 是一个接口,该消息似乎有些道理。 结果:实例化一个实现 classIModule。一个接口永远不能单独实现。
要实例化该类,只需更改一行:

Type moduleType = typeof(ClassThatImplementIModule);

您仍然可以将实例转换为 IModule

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。