0

我有一堆我想订阅的通用事件,并让它们都调用一个非通用方法。这是我的代码:

public delegate void PropertyChangedDelegate<OwnerType, PropertyType>(OwnerType sender, PropertyType oldValue, PropertyType newValue);

public class EventObject
{
    public event PropertyChangedDelegate<Object, Boolean> PropertyChanged;
                public event PropertyChangedDelegate<Object, Int32> XChanged;
}

static void Main()
{
    EventObject eventObject = new EventObject();
    EventInfo eventInfo = eventObject.GetType().GetEvent("PropertyChanged");
    eventInfo.AddEventHandler(eventObject, PropertyChanged);
}

    static void PropertyChanged(Object obj, Object oldValue, Object newValue)
    {
    }

显然这不起作用,有没有办法做一个包装泛型方法?

4

2 回答 2

1

问题是该PropertyChanged方法与类型不是逆变的,PropertyChangedDelegate因为发送boolobject需要装箱,因此很明显,您不能使委托对所有事件都通用。解决方法是写一个静态方法作为“落地方法”。这是我的解决方案:

using System;
using System.Reflection;

public delegate void PropertyChangedDelegate<OwnerType, PropertyType>(OwnerType sender, PropertyType oldValue, PropertyType newValue);

public class EventObject
{
    public event PropertyChangedDelegate<Object, Boolean> PropertyChanged;
    public event PropertyChangedDelegate<Object, Int32> XChanged;

    public void RaisePropertyChanged() {
        PropertyChanged(this, true, false);
    }
}

class Test {

    static void Main()
    {
        EventObject eventObject = new EventObject();
        EventInfo eventInfo = eventObject.GetType().GetEvent("PropertyChanged"); 
        Type evType = eventInfo.EventHandlerType;
        // replace below with this.GetType() in case of instance method
        Type thisType = typeof(Test); 
        MethodInfo mi = thisType.GetMethod("PropertyChanged", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
        MethodInfo genericMi = mi.MakeGenericMethod(evType.GetGenericArguments());
        Delegate del = Delegate.CreateDelegate(evType, genericMi);
        eventInfo.AddEventHandler(eventObject, del);
        // Test
        eventObject.RaisePropertyChanged();
    }

    static void PropertyChanged<TOwner, T>(TOwner obj, T oldValue, T newValue)
    {
        Console.WriteLine("-- Invoked --");
    }
}

灵感来自

使用反射获取静态方法及其参数

使用反射创建通用委托

于 2013-05-16T05:56:08.640 回答
0

您不能传递方法组来代替委托。您可以指定您的方法匹配的确切委托,如下所示:

EventObject eventObject = new EventObject();
EventInfo eventInfo = eventObject.GetType().GetEvent("PropertyChanged");
eventInfo.AddEventHandler(eventObject, (Action<Object, Object, Object>)PropertyChanged);

但它仍然会给你运行时异常,因为签名不匹配。

为什么不直接+=实现?

EventObject eventObject = new EventObject();
eventObject.PropertyChanged += PropertyChanged;

但是由于签名中的类型不匹配,这不会编译。您必须更改代表的签名

public delegate void PropertyChangedDelegate(Object sender, Object oldValue, Object newValue);

或更改事件的签名

public event PropertyChangedDelegate<Object, Object> PropertyChanged;

(但这会破坏您拥有强类型委托的所有努力)或更改方法的签名

static void PropertyChanged(Object obj, Boolean oldValue, Boolean newValue)
{
}

这就是我会去的。

于 2013-05-16T04:49:00.100 回答