在功能语言(如lisp)中,您可以使用模式匹配来确定列表中特定元素发生了什么。C#中的等效项将是一串if ... elseif语句,这些语句检查元素的类型并基于该元素执行操作。不用说,功能模式匹配比运行时类型检查更有效。
使用多态将更接近于模式匹配。也就是说,让列表的对象与特定接口匹配,然后在该接口上为每个对象调用一个函数。另一个选择是提供一系列重载方法,这些方法将特定对象类型作为参数。以Object为参数的默认方法。
public class ListVisitor
{
public void DoSomething(IEnumerable<dynamic> list)
{
foreach(dynamic obj in list)
{
DoSomething(obj);
}
}
public void DoSomething(SomeClass obj)
{
//do something with SomeClass
}
public void DoSomething(AnotherClass obj)
{
//do something with AnotherClass
}
public void DoSomething(Object obj)
{
//do something with everything els
}
}
这种方法提供了Lisp模式匹配的近似值。访问者模式(如此处实现的,是异构列表用法的一个很好的例子)。另一个示例是消息调度,其中优先级队列中有某些消息的侦听器,并使用责任链,调度程序传递消息,而与该消息匹配的第一个处理程序将其处理。
另一面是通知每个注册消息的人(例如,通常用于MVVM模式中ViewModel的松耦合的Event Aggregator模式)。我使用以下构造
IDictionary<Type, List<Object>>
添加到字典的唯一方法是函数
Register<T>(Action<T> handler)
(该对象实际上是对传入的处理程序的WeakReference)。所以在这里我必须使用List <Object>,因为在编译时,我不知道封闭类型是什么。但是,在运行时,我可以强制将Type作为字典的键。当我想触发事件时,我打电话给
Send<T>(T message)
再一次,我解析列表。使用List <dynamic>没有任何优势,因为无论如何我都需要进行转换。因此,如您所见,这两种方法都有其优点。如果要使用方法重载动态分派对象,则动态方法就是做到这一点。如果无论如何都强制转换,不妨使用Object。