столь же изящен как подход kvb).

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

class Invoker
{
    public object Invoke(object[] arg)
    {
        // generic handling code
    }
}

static void Main()
{
    var p = new Person();
    p.AddHandler("Event1", new Invoker().Invoke);
}

AddHandler это метод расширения дляobject которые получают имя события и делегат типаFunc<object[], object>, Он должен быть в состоянии сделать любую магию, чтобы связать событие (например,Event1 в данном случае) предоставленному делегату, чтобы делегат вызывался всякий раз, когда происходит событие.

ПодписьEvent1 не должно иметь значения, потому чтоAddHandler должен работать со всеми типами событий (и делегатами).

Я подозреваю, что это может потребовать некоторого поколения CIL для создания динамического делегата, соответствующего типу указанного события (например,Event1) и переадресация вызова указанному делегату (например,new Invoker().Invoke). Мне удалось создать такой динамический делегат, однако он мог только перенаправлять статические методы, а не методы экземпляра, потому что я не мог найти способ вставить связанный экземпляр вызываемого метода в стек CLR (т.е.Invoker экземпляр в примере). См. Приведенный ниже код, чтобы ясно увидеть эту проблему (см. Строку, помеченную ISSUE).

Если кто-то может указать способ улучшить код динамической генерации для захвата связанного объекта или еще лучше, предложите более простое решение, которое не требует CIL, тогда это очень ценится.

public static void AddHandler(this object target, string fieldName,
    Func<object[], object> func)
{
    var eventInfo = target.GetType().GetEvent(fieldName);
    if (eventInfo != null)
    {
        Type delegateType = eventInfo.EventHandlerType;
        var dynamicHandler = BuildDynamicHandler(target.GetType(), delegateType, func);
        eventInfo.GetAddMethod().Invoke(target, new Object[] { dynamicHandler });
    }
}

public static Delegate BuildDynamicHandler(this Type delegateOwnerType, Type delegateType, 
    Func<object[], object> func)
{
    MethodInfo invokeMethod = delegateType.GetMethod("Invoke");
    Type returnType = invokeMethod.ReturnType;
    bool hasReturnType = returnType != Constants.VoidType;
    var paramTypes = invokeMethod.GetParameters().Select(p => p.ParameterType).ToArray();
    var dynamicMethod = new DynamicMethod("add_handler",
                                            hasReturnType ? returnType : null, paramTypes, delegateOwnerType);

    var il = new EmitHelper(dynamicMethod.GetILGenerator());
    if (paramTypes.Length == 0)
    {
        il.ldnull.end();
    }
    else
    {
        il.DeclareLocal(typeof(object[]));
        il.ldc_i4(paramTypes.Length);
        il.newarr(typeof(object));
        il.stloc_0.end();
        for (int i = 0; i < paramTypes.Length; i++)
        {
            il.ldloc_0
                .ldc_i4(i)
                .ldarg(i)
                .boxIfValueType(paramTypes[i])
                .stelem_ref.end();
        }
        il.ldloc_0.end();
    }

    /////// ******************  ISSUE: work for static method only
    il.call(func.Method); 
    if (hasReturnType)
    {
        il.unbox_any(returnType).ret();
    }
    else
    {
        il.pop.ret();
    }
    return dynamicMethod.CreateDelegate(delegateType);
}

Ответы на вопрос(3)

Ваш ответ на вопрос