Попытка создать динамический делегат - PullRequest
4 голосов
/ 21 марта 2011

Я загружаю DLL, используя loadfrom и перебирая методы, чтобы найти те, которые соответствуют сигнатуре. Когда я нахожу это, я хочу назначить это как делегат, чтобы я мог вызвать это позже. Это то, что я делаю ...

foreach (MethodInfo method in methodInfos)
{
    if (method.GetParameters().Length == 2)
    {
        ParameterInfo[] parameters = method.GetParameters();
        if (parameters[0].ParameterType.Name == "Command" 
            && parameters[1].ParameterType.Name == "ExposedVariables")
        {
            aoc.methodinfo = method;
            Command.delCmdMethod del = (Command.delCmdMethod) 
                            Delegate.CreateDelegate(typeof(Command.delCmdMethod)
                                                   , null
                                                   , method);
        } 
     }
}

Проблема в том, что назначение делегата не работает. Я получаю сообщение об ошибке привязки к целевому методу.

Я читал в Интернете, что второй параметр может быть проблемой, если метод не является статическим. Мой метод НЕ статичен.

Есть идеи?

Ответы [ 2 ]

2 голосов
/ 30 мая 2011

Хотя ответ Мики Динеску может быть полезным, он только частично верен.Существует перегрузка для Delegate.CreateDelegate, которая, скорее всего, вам поможет.

Во-первых, Мики прав, что вы должны передать экземпляр в качестве второго параметра, но это толькослучай, если вы хотите создать то, что называется закрытый делегат .Это означает, что экземпляр связан с делегатом вместе с методом.На практике это означает, что при вызове делегата он всегда будет работать с одним и тем же экземпляром.

Судя по вашему вопросу, похоже, это не то, чего вы пытаетесь достичь.Если вы хотите иметь возможность передавать экземпляр при вызове делегата, вы должны использовать перегрузку CreateDelegate( Type type, MethodInfo method ).Это позволяет вам создать так называемый открытый экземплярный делегат .

Поскольку при вызове метода вам придется передавать экземпляр, это означает, что в вашем типе делегата требуется дополнительный параметр.Первый параметр вашего типа делегата должен соответствовать типу класса, в котором содержится метод.

Пример:

MethodInfo toUpperMethod
    = typeof( string ).GetMethod( "ToUpper", new Type[] { } );
Func<string, string> toUpper
    = (Func<string, string>)Delegate.CreateDelegate(
          typeof( Func<string, string> ), toUpperMethod );
string upper = toUpper( "test" ); // Will result in "TEST".

Поскольку - как и вы - я нашел этинеясные перегрузки, я создал две вспомогательные функции, чтобы четко разделить создание «нормального» делегата или делегата с открытым экземпляром.Этот код вместе с более подробным обсуждением можно найти в моем блоге .

0 голосов
/ 21 марта 2011

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

Если вы не знаете, какой экземпляр вы будете использовать в то время, когда вы пытаетесь создать делегата, вам нужно будет сохранить информацию о типе и методе на потом, а затем создать делегат после того, как вы получите экземпляр класс.

EDIT

Чтобы ответить на ваш комментарий, объект, который вам нужно передать, является объектом того типа, который содержит метод, к которому вы пытаетесь привязать своего делегата. Так что, исходя из вашего примера кода, это не объект Command, а объект класса из DLL.

Итак, допустим, у вас есть эта сборка .NET DLL: myassembly.dll. Сборка содержит следующий класс:

namespace MyNamespace
{
    public class SomeClass
    {
         public SomeClass()
         {
         } 

         public void Method1(object Command, object ExposedVariables)
         {
         }

         public void Method2(object Command, object ExposedVariables)
         {
         }
} 

Вам потребуется создать экземпляр класса SomeClass, прежде чем вы сможете создавать делегаты, связанные с Method1 или Method2 этого класса. Итак, код, который создает делегат, должен выглядеть так:

// assuming that method info is a MethodInfo contains information about the method
// that you want to create the delegate for, create an instance of the class which
// contains the method..
object classInstance = Activator.CreateInstance(methodInfo.DeclaringType);
// and then create the delegate passing in the class instance
Delegate.CreateDelegate(typeof(Command.delCmdMethod), classInstance, methodInfo);
...