在运行时加载程序集并使用Activator.CreateInstance()创建实例

14

我正在尝试在运行时加载一个程序集,但我不确定为什么使用静态 Activator.CreateInstance() 无法创建程序集中类型的实例。而使用 Assembly.CreateInstance() 则可以正常工作。

string assemblyFilename = "MyAssembly.dll";
string assemblyName = "MyAssembly";
string typeName = "MyAssembly.MyType";

FileInfo fileInfo = new FileInfo(assemblyFilename);

这个可行:

var assembly = Assembly.LoadFrom(assemblyFilename);
Form form = (Form)assembly.CreateInstance(typeName);

但是这个方法不起作用

Assembly.LoadFrom(assemblyFilename);
Form form = (Form)Activator.CreateInstance(assemblyName, typeName).Unwrap();

抛出FileNotFoundException异常:

无法加载文件或程序集'MyAssembly'或其某个依赖项。系统找不到指定的文件。

编辑:

在这两种情况下,在调用Assembly.LoadFrom()之后,当我查看AppDomain.CurrentDomain.GetAssemblies()时,我可以看到我的程序集已加载。


1
第二个版本应该指定完整的程序集名称,而不仅仅是显示名称,并在内部使用Assembly.Load()。这与LoadFrom()不同。可以使用fuslogvw.exe进行故障排除。 - Hans Passant
就像“MyAssembly,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = 5dc3e20777fed081”一样吗?我收到了相同的错误。 - Dave New
我甚至直接从GetAssemblies()中的"MyAssembly"复制了FullName,但仍然不起作用。太困惑了! - Dave New
1
@davenewza 还有一件事,尝试钩入AppDomain.Current的AssemblyResolve事件。当找不到程序集时,它应该会触发,也许你可以在那里看到它正在寻找的完整程序集名称。也许它无法找到你的MyAssembly使用的某个依赖项。 - armen.shimoon
1
@davenewza,还有一件事Dave,请尝试使用类型名称的程序集限定名,即:TopNamespace.SubNameSpace.ContainingClass+NestedClass,MyAssembly,Version=1.3.0.0,Culture=neutral,PublicKeyToken=b17a5c561934e089。 - armen.shimoon
4个回答

5

您可以通过调整其路径来调整文件

var path = Assembly.GetAssembly(MyType.GetType()).Location;
var thisAssembly= Assembly.LoadFrom(path);

var TypeName = "";
Type type = thisAssembly.GetType(TypeName);
object instance = Activator.CreateInstance(type);

我需要使用Activator.CreateInstance(),因为我并不总是有该程序集的实例可用。 - Dave New
如何在加载程序集后动态地创建一个类并定义其所有方法?由于我之前没有使用Using来加载它,所以在方法上获取了编译错误?谢谢。 - aleXela

4

你必须先将程序集加载到当前的AppDomain中:

AppDomain.CurrentDomain.Load(File.ReadAllBytes(assemblyFileName));

编辑:这有效吗?

Form form = (Form)Activator.CreateInstance(Type.GetType(typeName))

我遇到了同样的问题。如果我在Assembly.LoadFrom()之后查看AppDomain.CurrentDomain.GetAssemblies(),那么我可以看到我的程序集在两种情况下都已加载。 - Dave New
我得到了“值不能为 null”在 Type.GetType() 上。 - Dave New
1
Type.GetType(typeName) 返回 null,还是 typeName 本身就是 null? - armen.shimoon
1
使用AppDomain.Current.CreateInstance(assemblyName, typeName)怎么样? - armen.shimoon
目前不确定,我会确保所有的大小写都正确,否则我就得再想一晚上了。 - armen.shimoon
显示剩余2条评论

2

尝试编辑原回答,但作者没有回复。为了防止有人需要这个代码,这里是对我有效的代码。

System.Reflection.Assembly assembly = AppDomain.CurrentDomain.Load(File.ReadAllBytes("DLL_PATH"));  
Form form = (Form)assembly.CreateInstance("FullNameSpace.ClassName");

0

这是对A Khudairy的回答的变体,允许传递输入参数以访问特定构造函数,加上他的回答的这个变体解决了我遇到的问题,我已经在不断地搜索和解决这个问题几个星期了(非常感谢他分享答案)。

我的问题是,我想将一个.NET 3.5 dll加载到一个新的.NET 4.6应用程序中,但那些旧的dll使用第三方控件,看起来使用CAS策略。第三方控件会报错,说我需要在app.config中打开权限,如果我这样做,如果它们在我的本地计算机上,我可以正常加载和运行文件,但如果我尝试从网络驱动器加载它们(我需要这样做),那么我就会得到一个FileIOPermission错误。

尝试使用NetFx40_LegacySecurityPolicy与loadFromRemoteSources和useLegacyV2RuntimeActivationPolicy的组合,以及尝试了几种不同的方法,例如Activator.CreateInstance()(通常对我有效),尝试创建沙盒(虽然我不知道是否做得正确),但除了下面这个之外,什么都不起作用。请注意,我的用户控件也是基于一个基类的。在授予访问网络驱动器的权限之前,我运行了一些CAS命令提示符命令,并且我的应用程序应该在完全信任中运行。无论如何,除了这种方法之外,我尝试过的其他方法似乎都没有对我产生作用。

代码修复:

object dllUserControl = null;
System.Reflection.Assembly assembly = AppDomain.CurrentDomain.Load(File.ReadAllBytes("DLL_PATH"));  
dllUserControl = assembly.CreateInstance("FullNameSpace.ClassName",true,BindingFlags.Default,null,constructorParams[],null,null);

...从中我可以稍后将对象转换为所需的类型(到我的基类),以便稍后在其自己的表单/窗口中启动它。


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