我可以在运行时加载.NET程序集并实例化仅知道名称的类型吗?


178

如果我只有DLL名称和类名称,而没有在项目中添加对程序集的引用,是否可以在运行时实例化对象?该类实现一个接口,因此一旦实例化该类,便将其强制转换为该接口。

程序集名称:

库.dll

类型名称:

Company.Project.Classname


编辑:我没有DLL的绝对路径,所以Assembly.LoadFile将无法工作。DLL可能位于应用程序的根目录,system32中,甚至可能位于GAC中。

Answers:


221

是。您需要用于Assembly.LoadFrom将程序集加载到内存中,然后可以用于Activator.CreateInstance创建首选类型的实例。您需要首先使用反射查找类型。这是一个简单的示例:

Assembly assembly = Assembly.LoadFrom("MyNice.dll");

Type type = assembly.GetType("MyType");

object instanceOfMyType = Activator.CreateInstance(type);

更新资料

当您具有程序集文件名和类型名称时,可以Activator.CreateInstance(assemblyName, typeName)用来要求.NET类型解析将其解析为类型。您可以使用try / catch将其包装起来,以便在失败时可以对目录进行搜索,在其中可以专门存储其他程序集,否则可能无法搜索到其他程序集。此时将使用前面的方法。


2
我没有dll的绝对路径,所以assemlby.LoadFile等。不会工作,还有其他想法吗?
MegaByte

@rp总是很乐意提供帮助(只有这么晚才这么说!)
Jeff Yates 2010年

2
@MegaByte:LoadFrom与LoadFile不同。它将解析您的依赖关系,并且应从已知路径(GAC,exe目录等)解析DLL名称。有关更多信息,请参见MSDN。
杰夫·耶茨

1
还有一件事...(又是我)嗯,您不能只将“ MyType”作为类型名称,它后面必须要加上NAMESPACE。因此,这将更加准确:Type type = assembly.GetType("MyNamespace"+"."+"MyType");
Cipi

1
@Cipi:从技术上讲,类型是它的完整名称空间名称(名称空间的概念是一种语言上的便利)。您可以在CLR中使用没有名称空间的类型-我只是提供了一个过于简化的示例。
杰夫·耶茨

36

考虑不同Load*方法的局限性。从MSDN文档...

LoadFile不会将文件加载到LoadFrom上下文中,也不会像LoadFrom方法那样使用加载路径解析依赖项

有关负载上下文的更多信息,请参见LoadFrom文档。


19

Activator.CreateInstance应该可以工作。

IFace object = (IFace)Activator.CreateInstance( "AssemblyName",
                                                "TypeName" )
                               .Unwrap();

注意:类型名称必须是标准类型。

例:

var aray = (IList)Activator.CreateInstance("mscorlib","System.Collections.ArrayList").Unwrap();
aray.Add(10);

foreach (object obj in aray)
{
    Console.WriteLine(obj);
}

1
请注意:TypeName必须完全合格。我必须这样称呼:Activator.CreateInstance("MyAssembly","MyAssembly.TypeName") 并且返回一个ObjectHandle。要进入您的界面,您需要做ObjectHandle.UnWrap()
Anthony Sottile

7

我发现此问题和一些答案非常有用,但是我确实遇到了路径问题,因此此答案将通过查找bin目录路径来涵盖加载库。

第一个解决方案:

string assemblyName = "library.dll";
string assemblyPath = HttpContext.Current.Server.MapPath("~/bin/" + assemblyName);
Assembly assembly = Assembly.LoadFrom(assemblyPath);
Type T = assembly.GetType("Company.Project.Classname");
Company.Project.Classname instance = (Company.Project.Classname) Activator.CreateInstance(T);

第二解决方案

string assemblyName = "library.dll";
string assemblyPath = HttpContext.Current.Server.MapPath("~/bin/" + assemblyName);
Assembly assembly = Assembly.LoadFile(assemblyPath);
(Company.Project.Classname) instance = (Company.Project.Classname) assembly.CreateInstance("Company.Project.Classname");

您可以对接口使用相同的原理(您将创建一个类,但强制转换为接口),例如:

(Company.Project.Interfacename) instance = (Company.Project.Interfacename) assembly.CreateInstance("Company.Project.Classname");

此示例适用于Web应用程序,但类似示例可用于桌面应用程序,仅以不同的方式解析路径,例如

Path.GetDirectoryName(Application.ExecutablePath)

5

这很容易。

来自MSDN的示例:

public static void Main()
{
    // Use the file name to load the assembly into the current
    // application domain.
    Assembly a = Assembly.Load("example");
    // Get the type to use.
    Type myType = a.GetType("Example");
    // Get the method to call.
    MethodInfo myMethod = myType.GetMethod("MethodA");
    // Create an instance.
    object obj = Activator.CreateInstance(myType);
    // Execute the method.
    myMethod.Invoke(obj, null);
}

这是参考链接

https://msdn.microsoft.com/zh-CN/library/25y1ya39.aspx


这是支持动态加载代码的可怕方法。MS一直喜欢强迫我们进入太多细节。
清晰的

3

从Framework v4.5开始,您可以使用Activator.CreateInstanceFrom()轻松实例化程序集中的类。下面的示例演示如何使用它以及如何调用传递参数并获取返回值的方法。

    // Assuming moduleFileName contains full or valid relative path to assembly    
    var moduleInstance = Activator.CreateInstanceFrom(moduleFileName, "MyNamespace.MyClass");
    MethodInfo mi = moduleInstance.Unwrap().GetType().GetMethod("MyMethod");
    // Assuming the method returns a boolean and accepts a single string parameter
    bool rc = Convert.ToBoolean(mi.Invoke(moduleInstance.Unwrap(), new object[] { "MyParamValue" } ));


2
((ISomeInterface)Activator.CreateInstance(Assembly.LoadFile("somePath").GetTypes()[0])).SomeInterfaceMethod();

2

您可以使用* Assembly.Load **方法加载程序集。使用Activator.CreateInstance可以创建所需类型的新实例。请记住,您必须使用要加载的类的全类型名称(例如Namespace.SubNamespace.ClassName)。使用方法InvokeMember中的类型类,你可以调用该类型的方法。

另外,考虑到一旦加载,就不能卸载程序集,直到整个AppDomain也都卸载为止(这基本上是内存泄漏)。



2
Assembly assembly = Assembly.LoadFrom("MyAssembly.dll");

Type type = assembly.GetType("MyType");

dynamic instanceOfMyType = Activator.CreateInstance(type);

因此,通过这种方式,您可以将函数与获取methodinfo一起使用,然后对其进行调用。但是您不能使用Intellisense,因为动态类型是在运行时而不是在编译时键入的。


1

是的,是的,您将要在Assembly类上使用静态Load方法,然后调用,然后在对Load的调用中返回的Assembly实例上调用CreateInstance方法。

另外,您可以根据需要在Assembly类上调用其他以“ Load”开头的静态方法之一。


0

您可以通过以下方式执行此操作:

using System.Reflection;

Assembly MyDALL = Assembly.Load("DALL"); //DALL name of your assembly
Type MyLoadClass = MyDALL.GetType("DALL.LoadClass"); // name of your class
 object  obj = Activator.CreateInstance(MyLoadClass);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.