我有一个 WCF 服务,它接受任何实现接口(interface)的实体。当它收到这些实体之一时,我想发布一个事件,即
public void Receive(IFruit fruit)
{
messageHub.Publish(new FruitReceived<IFruit>(fruit));
}
但是我想具体化接口(interface),而不是所有处理水果的东西都订阅事件 FruitReceived<IFruit>
他们只能订阅他们感兴趣的类型,例如 FruitReceived<Apple>
.
目前我可以通过一些冗长的反射(reflection)来做到这一点:
var fruitType = fruit.GetType();
var evt = typeof(FruitReceived<>)
.MakeGenericType(fruitType)
.GetConstructor(fruitType)
.Invoke(fruit);
这对性能有一点影响(即使缓存了构造函数)并且也难以阅读。
我希望有一种更简单的方法来实现这一点?我花了很多时间思考这个解决方案,这是我唯一能想出的解决方案。
作为引用,发布方法简化为如下所示:
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
的实例但下游你想区分不同的具体类型。
将类转换为它实现的接口(interface)的好处是,消费者只需要知道声明的 类型是什么。他们知道这是一个 IFruit
这就是他们需要知道的全部。一旦他们需要了解更多信息, yield 就会减少。
换句话说,如果你关心 Apple
之间的区别和一个 Orange
那为什么要把它变成一个 IFruit
?当然,实现之间存在差异,但这些差异 - 甚至存在不同的实现 - 对任何依赖 IFruit
的事物都应该是透明的。 .
没有完美巧妙的方法来处理这个问题。如果您没有创建通用类型(如您的帖子中所示),那么您正在这样做:
if(fruit is Apple)
无论如何都会有类型创建或类型检查。
你可以移动这个问题。有一个处理 FruitReceived<IFruit>
的事件处理程序.然后该事件处理程序创建更具体的事件类型并重新引发它,以便更具体的事件处理程序可以捕获它。这样你就可以拥有特定于 Apple
的事件处理程序, Orange
等
它并不完美,但它将问题从引发事件的地方转移到另一个有助于引发更具体的事件类型的类。
另一个有益的原因是您的设计允许多个事件处理程序。所以可以想象你可以提高 FruitEvent<IFruit>
具体类型是 Apple
,所以你想要一个特定于苹果的事件处理程序,但你也想要一个通用的 IFruit
要执行的事件处理程序。如果您将事件转换为 FruitEvent<Apple>
在引发它之前,您将不会执行通用事件处理程序。
关于c# - 从接口(interface)构造具体类的泛型类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44374586/