Подтвердить что ты не робот

С# reflection - загрузить сборку и вызвать метод, если он существует

Я хочу загрузить сборку (ее имя хранится в строке), использовать отражение, чтобы проверить, имеет ли он метод под названием "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 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(...)?

Спасибо заранее.


ИЗМЕНИТЬ Я привел рабочий пример в качестве отдельного ответа ниже.

4b9b3361

Ответ 1

используйте отражение, чтобы проверить, имеет ли он метод под названием "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 и изменить его как таковой.

Ответ 2

Так как это, кажется, популярный вопрос, вот полный пример исходного кода о том, как это сделать.

Предположим, что у нас есть сборка образцов 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);

Ответ 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();