C# 反射 - 加载程序集并调用存在的方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14479074/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:57:03  来源:igfitidea点击:

C# reflection - load assembly and invoke a method if it exists

c#reflectioninvokemember

提问by w128

I want to load an assembly (its name is stored in a string), use reflection to check if it has a method called "CustomType MyMethod(byte[] a, int b)" and call it or throw an exception otherwise. I guess I should do something like this, but would appreciate if someone could offer same advice on how best to do it:

我想加载一个程序集(它的名称存储在一个字符串中),使用反射来检查它是否有一个名为“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);

Is this good enough, or are there better/faster/shorter ways? What about constructors, given that these methods are not static - can they simply be ignored?

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

When invoking void Methods(), is it ok to just write t.InvokeMember(...) or should you always do Object obj = t.InvokeMember(...)?

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

Thanks in advance.

提前致谢。



EDITI have provided a working example as a separate answer below.

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

采纳答案by Mike Perrenoud

use reflection to check if it has a method called "CustomType MyMethod(byte[] a, int b)" and call it or throw an exception otherwise

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

Your current code isn't fulfilling that requirement. But you can pretty easily with something like this:

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

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);

Is this good enough, or are there better/faster/shorter ways?

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

As far as I'm concerned this is the best way and there isn't really anything faster per say.

就我而言,这是最好的方法,而且实际上并没有比这更快的方法。

What about constructors, given that these methods are not static - can they simply be ignored?

考虑到这些方法不是静态的,构造函数呢?它们可以简单地被忽略吗?

You are still going to have to create an instance of tas shown in my example. This will use the default constructor with no arguments. If you need to pass arguments you can, just see the MSDN documentationand modify it as such.

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

回答by Talha

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);
                }
            }
        }

回答by w128

Since this seems to be a popular question, here's the complete source code example on how to do it.

由于这似乎是一个流行的问题,这里是有关如何执行此操作的完整源代码示例。

Suppose we have a sample assembly, MyAssembly.dll, with a class MyClass. We wish to dynamically load it and invoke its methods. MyAssemblycode:

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

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);
        }
    }
}

First, we would like to create an instance of the class using the constructor MyClass(int initialX, int initialY), then call the method public int MyMethod(int count, string text). Here's how you do it from another project (e.g. a console application):

首先,我们想使用构造函数创建类的实例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);
}

Calling the static method public static void StaticMethod(int count, float radius)looks like this:

调用静态方法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);

回答by Andres Jaramillo Ortiz

You can use dynamic type whose will be resolved in runtime.

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

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