不同类型的集合

给定以下界面:

public interface IEventHandler where TEvent : IEvent { void Process(TEvent @event); } 

我可以使用什么IEnumerable类型来存储TEvent不同的IEventHandler实现的集合?

即给出以下3个实现:

 public class BlahEvent1EventHandler : IEventHandler { ... } public class WhateverEvent1EventHandler : IEventHandler { ... } public class BlahEvent2EventHandler : IEventHandler { ... } 

我可以比一组物品做得更好吗?

  var handlers = new List { new BlahEvent1EventHandler(), new WhateverEvent1EventHandler(), new BlahEvent2EventHandler(), }; 

顺便说一句,已经看到一些其他的答案主张使用基类型或inheritance的非通用接口,但看不出在这种情况下如何增加大量的价值,除非我遗漏了什么。 是的,它会让我以一种稍微更安全的方式将它们全部添加到集合中,使用对象,但不会让我迭代它们并调用强类型的Process方法而不像我需要对象那样进行转换。

 public interface IEventHandler { } public interface IEventHandler : IEventHandler where TEvent : IEvent { void Process(TEvent @event); } 

如果我有IEnumerableIEnumerable我仍然需要IEnumerable

 foreach (var handler in _handlers.Cast<IEventHandler>()) { handler.Process(@event); } 

有关如何改善这一点的任何想法?

我认为这里最好的方法是使用OfType扩展方法并保留List,假设在编译时知道事件的类型; 仍然会有一个演员阵容,但你不会这样做,你只会获得可以实际处理该事件的条目。

可能你的设计不是最佳的。 尝试将需要事件类型特定行为的所有代码移动到事件,而不是在事件处理程序中实现它。 即让多态性为你工作。

 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. } 

UPDATE

让我们假设有一种方法可以按照您的意图定义列表

 var handlers = new List(); 

你会怎么演员?

 var handler = handlers[i]; // How to cast? ((?)handler).Process((?)evt); 

也许更好的方法是每个事件类型有一个列表

 public static class EventHandler : IEventHandler where TEvent : IEvent { public static readonly List> Handlers = new List>(); ... } 

然后你可以访问这样的事件处理程序

 SpecificEventType specEvent = ...; EventHandler.Handlers[0].Process(specEvent); 

更新#2

一个完全不同的解决方案创建了一个新的集合类,它封装了弱类型列表,并通过使用generics方法提供强类型接口

 public class HandlerCollection : IEnumerable { private readonly List _handlers = new List(); public void Add(IEventHandler handler) where TEvent : IEvent { _handlers.Add(handler); } public IEventHandler Find() where TEvent : IEvent { return _handlers .OfType>() .FirstOrDefault(); } public IEventHandler Find(Func, bool> predicate) where TEvent : IEvent { return _handlers .OfType>() .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 eh = handlers.Find(); 

如果您需要通过处理程序枚举并调用其Process接口成员,那么您可以像这样实现您的类:

 public class BlahEvent1EventHandler : IEventHandler { ... } public class WhateverEvent1EventHandler : IEventHandler { ... } public class BlahEvent2EventHandler : IEventHandler { ... } public class Event1 : IEvent {} public class Event2 : IEvent {} 

然后使用它们:

 List> list = new List>(); list.Add(new BlahEvent1EventHandler()); foreach (IEventHandler eventHandler in list) { eventHandler.Process(new Event1()); }