给出以下界面:
public interface IEventHandler<in TEvent> where TEvent : IEvent
{
void Process(TEvent @event);
}
我可以使用哪种IEnumerable类型来存储TEvent不同的IEventHandler<TEvent>
实现集合?
即。鉴于以下3个实现:
public class BlahEvent1EventHandler : IEventHandler<Event1>
{
...
}
public class WhateverEvent1EventHandler : IEventHandler<Event1>
{
...
}
public class BlahEvent2EventHandler : IEventHandler<Event2>
{
...
}
我可以做一些比对象更好的事吗?
var handlers = new List<object>
{
new BlahEvent1EventHandler(),
new WhateverEvent1EventHandler(),
new BlahEvent2EventHandler(),
};
BTW,已经看到一些其他的答案主张使用基类型或继承的非通用接口,但看不出在这种情况下如何增加大量的价值,除非我遗漏了什么。是的,它允许我以一种稍微更安全的方式将它们全部添加到集合中,使用对象,但不会让我迭代它们并调用强类型的Process方法而不像我需要对象那样进行转换。 / p>
public interface IEventHandler
{
}
public interface IEventHandler<in TEvent> : IEventHandler where TEvent : IEvent
{
void Process(TEvent @event);
}
如果我有IEnumerable<IEventHandler>
或IEnumerable<obect>
foreach (var handler in _handlers.Cast<IEventHandler<TEvent>>())
{
handler.Process(@event);
}
有关如何改善这一点的想法吗?
答案 0 :(得分:3)
我认为这里最好的方法是使用OfType扩展方法并保留你的List,假设在编译时知道事件的类型;仍然会有一个演员阵容,但你不会这样做,你只会获得可以实际处理该事件的条目。
答案 1 :(得分:1)
可能你的设计不是最佳的。尝试将需要事件类型特定行为的所有代码移动到事件,而不是在事件处理程序中实现它。即让多态性为你工作。
public interface IEventHandler
{
void Process(IEvent evt);
}
作为示例,我们假设您需要根据特定于事件的属性创建消息。而不是在事件处理程序内部构造消息,而是在事件
中构造它public interface IEvent
{
string Message { get; }
...
}
特定事件
public class TestEvent : IEvent
{
public string A { get; set; } // Event specific property
public string B { get; set; } // Event specific property
public string Message { get { return String.Format("{0} {1}", A, B); } }
// The event handler does not need to access A or B.
}
<强>更新强>
我们假设有一种方法可以按照您想要的方式定义列表
var handlers = new List<?>();
你会怎么演员?
var handler = handlers[i];
// How to cast?
((?)handler).Process((?)evt);
也许更好的方法是每个事件类型都有一个列表
public static class EventHandler<in TEvent> : IEventHandler<TEvent>
where TEvent : IEvent
{
public static readonly List<IEventHandler<TEvent>> Handlers =
new List<IEventHandler<TEvent>>();
...
}
然后你可以像这样访问一个事件处理程序
SpecificEventType specEvent = ...;
EventHandler<SpecificEventType>.Handlers[0].Process(specEvent);
更新#2
完全不同的解决方案创建一个新的集合类,它封装弱类型列表并使用泛型方法提供强类型接口
public class HandlerCollection : IEnumerable
{
private readonly List<object> _handlers = new List<object>();
public void Add<TEvent>(IEventHandler<TEvent> handler)
where TEvent : IEvent
{
_handlers.Add(handler);
}
public IEventHandler<TEvent> Find<TEvent>()
where TEvent : IEvent
{
return _handlers
.OfType<IEventHandler<TEvent>>()
.FirstOrDefault();
}
public IEventHandler<TEvent> Find<TEvent>(Func<IEventHandler<TEvent>, bool> predicate)
where TEvent : IEvent
{
return _handlers
.OfType<IEventHandler<TEvent>>()
.Where(predicate)
.FirstOrDefault();
}
// Collection initializers can only be applied to types implementing IEnumerable
IEnumerator IEnumerable.GetEnumerator()
{
return _handlers.GetEnumerator();
}
}
测试
var handlers = new HandlerCollection {
new BlahEvent1EventHandler(),
new WhateverEvent1EventHandler(),
new BlahEvent2EventHandler()
};
IEventHandler<WhateverEvent1> eh = handlers.Find<WhateverEvent1>();
答案 2 :(得分:0)
如果您需要通过处理程序枚举并调用其Process接口成员,那么您可以像这样实现类:
public class BlahEvent1EventHandler : IEventHandler<IEvent>
{
...
}
public class WhateverEvent1EventHandler : IEventHandler<IEvent>
{
...
}
public class BlahEvent2EventHandler : IEventHandler<IEvent>
{
...
}
public class Event1 : IEvent
{}
public class Event2 : IEvent
{}
然后使用它们:
List<IEventHandler<IEvent>> list = new List<IEventHandler<IEvent>>();
list.Add(new BlahEvent1EventHandler());
foreach (IEventHandler<IEvent> eventHandler in list)
{
eventHandler.Process(new Event1());
}