C# 反射 - 加载程序集并调用方法(如果存在)

Posted

技术标签:

【中文标题】C# 反射 - 加载程序集并调用方法(如果存在)【英文标题】:C# reflection - load assembly and invoke a method if it exists 【发布时间】:2013-01-23 11:52:05 【问题描述】:

我想加载一个程序集(它的名称存储在一个字符串中),使用反射检查它是否有一个名为“CustomType MyMethod(byte[] a, int b)”的方法并调用它或抛出异常.我想我应该做这样的事情,但如果有人能就如何最好地做到这一点提供相同的建议,我将不胜感激:

Assembly asm = Assembly.Load("myAssembly"); /* 1. does it matter if write myAssembly or myAssembly.dll? */

Type t = asm.GetType("myAssembly.ClassName");

// specify parameters
byte[] a = GetParamA();
int b = GetParamB();

object[] params = new object[2];
params[0] = a;
params[1] = b;

/* 2. invoke method MyMethod() which returns object "CustomType" - how do I check if it exists? */
/* 3. what's the meaning of 4th parameter (t in this case); MSDN says this is "the Object on which to invoke the specified member", but isn't this already accounted for by using t.InvokeMember()? */
CustomType result = t.InvokeMember("MyMethod", BindingFlags.InvokeMethod, null, t, params);

这是否足够好,还是有更好/更快/更短的方法?那么构造函数呢,考虑到这些方法不是静态的——它们可以被忽略吗?

在调用 void Methods() 时,可以只写 t.InvokeMember(...) 还是应该始终使用 Object obj = t.InvokeMember(...)?

提前致谢。


编辑 我在下面提供了一个工作示例作为单独的答案。

【问题讨论】:

第四个参数是实例。类型 t 是类型,类。你需要先实例化它。 您应该将您的答案作为答案,而不是对问题的编辑。它对未来的读者来说更加清晰,并允许对您的答案进行评分,以便其他人可以看到它有多好。 @danio 你说得对,我差点忘了这个。完成。 【参考方案1】:

由于这似乎是一个流行的问题,这里有完整的源代码示例说明如何做到这一点。

假设我们有一个示例程序集,MyAssembly.dll,它有一个类 MyClass。我们希望动态加载它并调用它的方法。 MyAssembly 代码:

namespace MyAssembly

    public class MyClass
    
        public int X  get; set; 
        public int Y  get; set; 

        public MyClass(int initialX, int initialY)
        
            X = initialX;
            Y = initialY;
        

        public int MyMethod(int count, string text)
        
            Console.WriteLine("This is a normal method.");
            Console.WriteLine("Count: 0", count);
            Console.WriteLine("Text: 0", text);

            return this.X + this.Y;
        

        public static void StaticMethod(int count, float radius)
        
            Console.WriteLine("This is a static method call.");
            Console.WriteLine("Count: 0", count);
            Console.WriteLine("Radius: 0", radius);
        
    

首先,我们想使用构造函数MyClass(int initialX, int initialY)创建一个类的实例,然后调用方法public int MyMethod(int count, string text)。以下是您从另一个项目(例如控制台应用程序)执行此操作的方法:

static void Main(string[] args)

    //
    // 1. Load assembly "MyAssembly.dll" from file path. Specify that we will be using class MyAssembly.MyClass
    //
    Assembly asm = Assembly.LoadFrom(@"C:\Path\MyAssembly.dll");
    Type t = asm.GetType("MyAssembly.MyClass");

    //
    // 2. We will be invoking a method: 'public int MyMethod(int count, string text)'
    //
    var methodInfo = t.GetMethod("MyMethod", new Type[]  typeof(int), typeof(string) );
    if (methodInfo == null)
    
        // never throw generic Exception - replace this with some other exception type
        throw new Exception("No such method exists.");
    

    //
    // 3. Define parameters for class constructor 'MyClass(int initialX, int initialY)'
    //
    object[] constructorParameters = new object[2];
    constructorParameters[0] = 999; // First parameter.
    constructorParameters[1] = 2;   // Second parameter.

    //
    // 4. Create instance of MyClass.
    //
    var o = Activator.CreateInstance(t, constructorParameters);

    //
    // 5. Specify parameters for the method we will be invoking: 'int MyMethod(int count, string text)'
    //
    object[] parameters = new object[2];
    parameters[0] = 124;            // 'count' parameter
    parameters[1] = "Some text.";   // 'text' parameter

    //
    // 6. Invoke method 'int MyMethod(int count, string text)'
    //
    var r = methodInfo.Invoke(o, parameters);
    Console.WriteLine(r);

调用静态方法public static void StaticMethod(int count, float radius)如下所示:

var methodInfoStatic = t.GetMethod("StaticMethod");
if (methodInfoStatic == null)

    // never throw generic Exception - replace this with some other exception type
    throw new Exception("No such static method exists.");


// Specify parameters for static method: 'public static void MyMethod(int count, float radius)'
object[] staticParameters = new object[2];
staticParameters[0] = 10;
staticParameters[1] = 3.14159f;

// Invoke static method
methodInfoStatic.Invoke(o, staticParameters);

【讨论】:

在您的静态方法示例中,o 来自哪里? methodInfoStatic.Invoke(o, staticParameters); @theonlygusti 我已经有一段时间没有写了,但是 IIRC o 与上面的示例相同,但由于这是一个静态方法,如果我没记错的话,你可以简单地通过null 而不是o 在第 1 节的这一行:Type t = asm.GetType("MyAssembly.MyClass")“MyAssembly”需要来自项目的根命名空间属性,而不是来自程序集名称属性,在我的项目中是不同的(通常它们是相同,因为它们默认为相同的值,所以你通常不会有问题)。【参考方案2】:

使用反射检查它是否有一个名为“CustomType MyMethod(byte[] a, int b)”的方法并调用它或抛出异常

您当前的代码不满足该要求。但是你可以很容易地用这样的东西:

var methodInfo = t.GetMethod("MyMethod", new Type[]  typeof(byte[]), typeof(int) );
if (methodInfo == null) // the method doesn't exist

    // throw some exception


var o = Activator.CreateInstance(t);

var result = methodInfo.Invoke(o, params);

这是否足够好,还是有更好/更快/更短的方法?

就我而言,这是最好的方法,而且真的没有比说更快的方法了。

既然这些方法不是静态的,那么构造函数呢?它们可以简单地被忽略吗?

您仍然需要创建t 的实例,如我的示例所示。这将使用不带参数的默认构造函数。如果您需要传递参数,只需查看MSDN documentation 并对其进行修改即可。

【讨论】:

【参考方案3】:
Assembly assembly = Assembly.LoadFile("myAssembly");
        Type type = assembly.GetType("myAssembly.ClassName");
        if (type != null)
        
            MethodInfo methodInfo = type.GetMethod("MyMethod");
            if (methodInfo != null)
            
                object result = null;
                ParameterInfo[] parameters = methodInfo.GetParameters();
                object classInstance = Activator.CreateInstance(type, null);
                if (parameters.Length == 0)
                
                    //This works fine
                    result = methodInfo.Invoke(classInstance, null);
                
                else
                
                    object[] parametersArray = new object[]  "Hello" ;

                    //The invoke does NOT work it throws "Object does not match target type"             
                    result = methodInfo.Invoke(classInstance, parametersArray);
                
            
        

【讨论】:

【参考方案4】:

您可以使用将在运行时解析的动态类型。

Type type = Type.GetType(className, true);
dynamic instance = Activator.CreateInstance(type);
var response = instance.YourMethod();

【讨论】:

type是静态类的时候怎么用? 你不能实例化一个静态类,但你可以调用它的方法之一。 看:Activator and static classes

以上是关于C# 反射 - 加载程序集并调用方法(如果存在)的主要内容,如果未能解决你的问题,请参考以下文章

C#反射实例学习及注意内容

在运行时加载程序集并调用方法并卸载程序集

C#基础系列 - 反射基础

C#使用反射加载多个程序集

c#简易反射调用泛型方法

C#反射实例化类并调用类的方法