在运行时加载引用调用程序集的程序集

8
我的应用程序加载位于其执行路径中的所有库程序集,并针对包含的类执行预知方法。
现在,我需要对引用我的应用程序程序集的程序集执行相同的操作。这是否可行,是否存在我应该意识到的任何负面影响?
主要程序集:
public abstract class TaskBase 
{ 
    public abstract void DoWork(); 
}  

LoadAssemblyFromFile("Assembly0001.dll");  
Assembly0001.Task1.DoWork();  

子程序集:

public sealed class Task1: MasterAssembly.TaskBase  
{ 
    public override void DoWork { /* whatever */ } 
}

我一直这样做而没有任何问题。我遇到的唯一陷阱(实际上是几次)是管理“主”程序集的版本。如果您在没有重新编译子级别的情况下更改了“主”程序集,可能会遇到一些奇怪的问题。 - M.Babcock
@M.Babcock:谢谢。出于好奇,是什么样的问题?我在重新编译时不会自动增加程序集版本。我假设这应该可以避开你可能遇到的任何问题。你有什么想法? - Raheel Khan
我遇到的最常见的问题是方法定义的更改破坏了向后兼容性,但在其他情况下,我经历了可怕的“_Type_在_Master_和_Master_中都有定义”异常(从记忆中得知,因此不是文字上的描述,但足够接近以至于你能够认出它)。 - M.Babcock
4个回答

6

是的,这是可能的。只要您的主汇编不引用子汇编,那么就应该没问题。否则,您将有一个循环依赖。

主汇编将简单地加载子汇编,并且除了它们实现一个接口之外,对它们一无所知。这样,主汇编就不需要引用子汇编。

据我所知,没有任何陷阱。我们成功地在某些情况下使用此技术。


谢谢。在没有程序集文件存在于磁盘上的情况下,有没有一种从内存中加载程序集的方法?这些定期发布的程序集存在于一个中央数据库中,我希望让用户难以获取它们。当然,我知道没有绝对可靠的方法来实现这一点。 - Raheel Khan
是的,我们有类似那样的移动应用程序。汇编二进制代码存储在数据库中,通过检索和加载来实现。您也可以这样做。 - Bob Horn
找到了:Assembly.Load(byte[])。 - Raheel Khan

1
根据我的经验,这种做法没有任何问题。事实上,MEF使用了这种技术,以AssemblyCatalog的形式(其中你的实现在主程序集中)和DirectoryCatalog的形式(其中接口的实现在特定目录的程序集中)。两者可以一起在AggregateCatalog中使用,没有任何问题。

0
你没有发布 LoadAssemblyFromFile("...") 方法的代码,但如果它使用 Assembly.LoadFrom() 或 Assembly.LoadFile() 来加载程序集,你可能会遇到 InvalidCastException、MissingMethodException 或其他异常,特别是当你的应用程序和已加载的程序集都引用相同的其他程序集时。LoadFrom() 和 LoadFile() 在不同的绑定上下文中加载程序集,与你的应用程序所在的上下文不同。详见 this

0
唯一的“问题”是您无法在主程序集中编写Assembly0001.Task1,但您可以在已加载的程序集中找到正确的任务并调用它:
var asm = LoadAssemblyFromFile("Assembly0001.dll");
var taskType = asm.GetTypes().FirstOrDefault(t => typeof(TaskBase).IsAssignableFrom(t));
var task = (TaskBase)Activator.CreateInstance(taskType);
task.DoWork();

你仍然需要添加一些额外的安全检查 :)


当然可以。通过类型创建运行时实例是实现这一目标的唯一方法。您会推荐哪些安全检查?应用程序确实需要确保它正在执行我们自己的代码(可能是通过单向哈希)。还有什么? - Raheel Khan
主要是空值检查,如果你真的想为运行任务创建一个沙盒,那就会变得有点困难。 - XIU

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接