Как создать делегат цели с переменным числом аргументов

предположим есть метод, который принимает переменное количество аргументов:

void Target( params object[] args );

чтобы присоединить это к действию с конкретным списком параметров, мы можем создать лямбда-выражение:

Action<int, int> someAction += (a, b) => Target(a, b);

есть ли возможность создать это лямбда-выражение динамически, чтобы иметь возможность присоединить обработчик к любому типу события? Что-то вроде:

someAction += CreateDelegate( typeof(someAction), Target );

Я пытался использовать Delegate.CreateDelegate но он ожидает, что целевой метод в конкретный список аргументы. У меня такое чувство, что это должно быть возможно с Expression.Lambda но пока у меня не было никакого успеха. У тебя есть идея?

редактировать

переименовал событие в действие и обработчик в target.

2 ответов


делегат для этого метода:

void Handle( params object[] args );

будет Action<object[]>, так как делегаты не могут использовать params модификатор. Вам нужно будет сделать то, что делает компилятор, и сопоставить другой метод в массив объектов.

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


Я взглянул на выражения за лямбдой, проанализировав следующую строку:

Expression<Action<int, int>> ex = (a, b) => Target(a, b);

на основе этого я создал собственную фабрику делегат:

public static Delegate CreateDelegate( Type delegateType, Action<object[]> target )
{
    var sourceParameters = delegateType.GetMethod("Invoke").GetParameters();

    var parameters = sourceParameters.Select( p => Expression.Parameter( p.ParameterType, p.Name ) ).ToArray();

    var castParameters = parameters.Select(p => Expression.TypeAs(p, typeof(object))).ToArray();

    var createArray = Expression.NewArrayInit(typeof(object), castParameters);

    var invokeTarget = Expression.Invoke(Expression.Constant(target), createArray);

    var lambdaExpression = Expression.Lambda( delegateType, invokeTarget, parameters);

    return lambdaExpression.Compile();
 }