我有一个WCF服务,它接受实现接口的任何实体。当它收到这些实体之一时,我想发布一个事件,即

public void Receive(IFruit fruit)
{
      messageHub.Publish(new FruitReceived<IFruit>(fruit));
}


但是,我想对接口进行优化,因此,除了可以处理水果订阅事件FruitReceived<IFruit>的所有内容外,它们还可以仅订阅他们感兴趣的类型,例如FruitReceived<Apple>

目前,我可以通过一些漫长的思考来做到这一点:

var fruitType = fruit.GetType();
var evt = typeof(FruitReceived<>)
    .MakeGenericType(fruitType)
    .GetConstructor(fruitType)
    .Invoke(fruit);


这会影响性能(即使在缓存构造函数时也是如此),而且很难阅读。

我希望有一种更简单的方法来实现这一目标?我花了很多时间考虑这种解决方案,这是我唯一能想到的解决方案。

作为参考,publish方法简化为以下形式:

public void Publish<TEvent>(TEvent evt)
{
    if(_subscriptions.ContainsKey(typeof(TEvent))
    {
        IEnumerable<IEventHandler<TEvent>> handlers = _subscriptions[typeof(TEvent)];

        foreach(var handler in handlers)
        {
            handler.HandleEvent(evt);
        }
    }
}

最佳答案

潜在的问题似乎是您正在接收IFruit的实例,但是在下游您想区分不同的具体类型。

将类强制转换为它实现的接口的好处是,消费者只需要知道声明的类型是什么即可。他们知道这是一个IFruit,这就是他们需要知道的全部。一旦他们需要了解的更多,收益就会减少。

换句话说,如果您完全关心AppleOrange之间的区别,那么为什么将其转换为IFruit?当然,实现之间存在差异,但是这些差异-甚至存在不同的实现-对于依赖IFruit的任何事物都应该透明。

没有完美的方法可以解决这个问题。如果您没有创建泛型类型(如您的文章中所述),则可以这样做:

if(fruit is Apple)


无论如何,都会进行类型创建或类型检查。

您可以解决问题。有一个处理FruitReceived<IFruit>的事件处理程序。然后,该事件处理程序创建更具体的事件类型并重新引发它,以便更具体的事件处理程序可以捕获它。这样,您可以拥有特定于AppleOrange等的事件处理程序。

这不是完美的方法,但是它将问题从引发事件的位置转移到了另一个有助于引发更具体事件类型的类。

这样做有好处的另一个原因是您的设计允许使用多个事件处理程序。因此可以想象,您可以在具体类型为FruitEvent<IFruit>的情况下引发Apple,因此,您需要特定于苹果的事件处理程序,但还希望执行通用的IFruit事件处理程序。如果在引发事件之前将事件转换为FruitEvent<Apple>,则不会执行通用事件处理程序。

关于c# - 从接口(interface)构造具体类的泛型类,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44374586/

10-11 01:07