C # «не удалось найти» существующий метод - PullRequest
1 голос
/ 17 января 2011

Привет!Я (немного) дурачился с C # и его сборками.И вот я обнаружил такую ​​интересную особенность, как динамическая загрузка сборок и вызов членов этого класса.Немного о гугле, и вот я здесь, пишу что-то вроде "проводника сборок".(Я использовал некоторые части кода из здесь , здесь и здесь , и никто из них не дал ожидаемых результатов).

Но я обнаружил небольшую ошибку: когда я пытался вызвать метод класса из сборки, которую я загрузил, приложение вызвало исключение MissingMethod.Я уверен, что DLL, которую я загружаю, содержит класс и метод, который я пытаюсь вызвать (мое приложение обеспечивает мне, а также .NET Reflector RedGate ):

alt text

Основной код приложения, кажется, в порядке, и я начинаю думать, если я ошибся с моей DLL ... Ах, и я поместил оба проекта в одно решение, но я не думаю, что это может привести клюбые проблемы.И да, у проекта DLL есть цель «библиотека классов», в то время как у основного приложения есть цель «консольное приложение».

Итак, вопрос: что не так с em?

Вот некоторый исходный код:

Источник DLL:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClassLibrary1
{
    public class Class1
    {
        public void Main()
        {
            System.Console.WriteLine("Hello, World!");
        }
    }
}

Основной источник приложения:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly asm = Assembly.LoadFrom(@"a\long\long\path\ClassLibrary1.dll");

            try
            {
                foreach (Type t in asm.GetTypes())
                {
                    if (t.IsClass == true && t.FullName.EndsWith(".Class1"))
                    {
                        object obj = Activator.CreateInstance(t);
                        object res = t.InvokeMember("Main", BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, null); // Exception is risen from here
                    }
                }
            }
            catch (Exception e)
            {
                System.Console.WriteLine("Error: {0}", e.Message);
            }

            System.Console.ReadKey();
        }
    }
}

UPD: работал для одного случая - когда метод DLL не принимает аргументов:

Класс DLL (также работает, если метод не является статическим):

public class Class1
{
    public static void Main()
    {
        System.Console.WriteLine("Hello, World!");
    }
}

Код вызова метода:

object res = t.InvokeMember("Main", BindingFlags.Default | BindingFlags.InvokeMethod, null, null, null);

Ответы [ 3 ]

4 голосов
/ 17 января 2011

Почему вы создаете экземпляр (Activator.CreateInstance(t)) для вызова статического метода ????Это должно быть:

t.InvokeMember(
     "Main", 
     BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, 
     null, 
     null, 
     new object[] { new string[0] }
);

Кроме того, этот метод, как определено, не возвращает никакого значения, поэтому нет необходимости присваивать ему возвращаемую переменную.

И для устранения всех недоразумений, которые я имеюсоздал полную рабочую демо здесь: http://www.mediafire.com/?n7h9b8ghomfv17d

3 голосов
/ 17 января 2011

Вероятно, вы неверно получаете аргументы InvokeMember ().Вот пример, который работает:

using System;
using System.Reflection;

class Program {
    static void Main(string[] args) {
        if (args.Length > 0) Console.WriteLine(args[0]);
        else {
            Assembly asm = Assembly.LoadFrom(Assembly.GetEntryAssembly().Location);
            foreach (Type t in asm.GetTypes()) {
                if (t.IsClass == true && t.FullName.EndsWith(".Program")) {
                    //object obj = Activator.CreateInstance(t);
                    object res = t.InvokeMember("Main",
                        BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod,
                        null, null,
                        new object[] { new string[] { "Invoked" } });
                }
            }
        }
    }
}
  • Обратите внимание, что метод Main () не является публичным, поэтому BindingFlags.NonPublic
  • Обратите внимание, что метод Main () является статическим,таким образом BindingFlags.Static
  • По той же причине передайте значение null для target параметр
  • По той же причине CreateInstance не требуется
  • Примечаниекак метод Main () принимает аргумент string [], вы должны передать его, чтобы получить Reflection, чтобы найти правильную перегрузку метода.

Следуйте той же логике для вашего метода Main ():

                object res = t.InvokeMember("Main",
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod,
                    null, obj,
                    new object[] { });
2 голосов
/ 17 января 2011

Последний параметр для InvokeMember является массивом объектов, содержащих аргументы метода.

Вы передаете туда null, вам следует передать массив объектов, содержащий один элемент (массив строк).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...