将委托引用传递给另一个类,以便一个订阅者可以收听多个发布者?

时间:2018-02-25 09:30:17

标签: c# events delegates

我正在考虑事件/委托系统的更复杂用途,并且有一个我无法找到解决方案的用例。

假设我有两个类都处理从同一个基类继承的对象:

public class VegetableStore {
    List<VegType> vegtypes;
}
public class MeatStore {
    List<MeatType> meatTypes;
}
// MeatType and VegType both extend abstract class FoodType

在一个单独的类中,我想在每次将一个新的VegType添加到VegetableStore中时监听,或者将新的MeatType添加到MeatStore。

现在,“简单”的方式似乎只是这样:

public class VegetableStore {
        List<VegType> vegtypes;
        public delegate void VegTypeAddedEventHandler(VegType vegType, bool added);
        public event VegTypeAddedEventHandler VegTypeAdded;

        //...
        protected virtual void OnVegTypeAdded(VegType vegType, bool added) {}
}
public class MeatStore {
        List<MeatType> meatTypes
        public delegate void MeatTypeAddedEventHandler(MeatType meatType, bool added);
        public event MeatTypeAddedEventHandler MeatTypeAdded;

        //...
        protected virtual void OnMeatTypeAdded(MeatType meatType, bool added) {}
}

然后在我的听众课上......

vegStore.VegTypeAdded += OnFoodTypeAdded;
meatStore.MeatTypeAdded += OnFoodTypeAdded;

void OnFoodTypeAdded(FoodType foodType, bool added) {}

尽管如此,这感觉要麻烦得多。

我想做的是拥有某种“父”代表,例如FoodTypeAddedEventHandler(object source, EventArgs e) 然后能够自动订阅订阅此事件的任何事件,订阅来自Meat和Veg的事件,这样我就可以包含一个中间事件管理器类

public event FoodTypeAddedEventHandler FoodTypeAdded
{
    add
    {
        vegStore.VegTypeAdded += value;
        meatStore.MeatTypeAdded += value;
    {
    remove
    {
        vegStore.VegTypeAdded -= value;
        meatStore.MeatTypeAdded -= value;
    }
}

麻烦的是。 vegStore和meatStore没有FoodTypeAddedHandler类型的委托,因此导致类型错误。

有没有切实可行的方法呢?似乎无法找到这个问题的合理直接的解决方案,但我觉得必须有一个。或者,我应该亲了吗?

1 个答案:

答案 0 :(得分:2)

您可以使用这样的通用委托:

delegate void FoodTypeAddedEventHandler<in T>(T meatType, bool added) where T : FoodType;

然后代替VegTypeAddedEventHandler,您拥有FoodTypeAddedEventHandler<VegType>而不是MeatTypeAddedEventHandler,而FoodTypeAddedEventHandler<MeatType>代替FoodTypeAddedEventHandler。最后代替FoodTypeAddedEventHandler<FoodType>,您有public event FoodTypeAddedEventHandler<FoodType> FoodTypeAdded { add { vegStore.VegTypeAdded += value; meatStore.MeatTypeAdded += value; { remove { vegStore.VegTypeAdded -= value; meatStore.MeatTypeAdded -= value; } } 。经过这些修改,你的&#34;结合了#34;事件处理程序将编译正常:

Action<FoodType, bool>

或者 - 只需删除所有代理类型,然后使用Action<VegType, bool>Action<MeetType, bool>T。那么你的代码也可以正常编译。

这是有效的,因为两个自定义委托都有第一个类型参数(in)逆变(FoodTypeAddedEventHandler<FoodType>修饰符)。这允许它接受派生类型的参数(因此,委托FoodType可以接受签名,其中第一个参数不是VegType,而是任何派生类型(例如Action)。同样适用于Action因为在in中所有类型参数都是逆变的(使用 private val socketListeners: ArrayList<SocketContentListener> = ArrayList() //add listener here override fun subscribe(socketListener: SocketContentListener) { socketListeners.add(socketListener) } private fun getSocketConnectListener() : SocketContentListener { /** * Post received messages to listeners via Handler * because handler helps to set all messages in order on main thread. */ return object : SocketContentListener { override fun onUdpServerListenerCreated(inetAddress: InetAddress?, port: Int) { val subscribers = ArrayList<SocketContentListener>(socketListeners) for (listener in subscribers) { Handler(Looper.getMainLooper()).post({ listener.onUdpServerListenerCreated(inetAddress, port) }) } } } 修饰符声明)。有关您可以在documentation中阅读的代理中的差异的更多信息。