В функциональных языках (таких как 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. Шаблон посетителей (реализованный здесь, является отличным примером использования для разнородных списков). Другим примером может быть диспетчеризация сообщений, когда в очереди с приоритетами находятся прослушиватели для определенных сообщений, и, используя цепочку ответственности, диспетчер передает сообщение, а первый обработчик, соответствующий сообщению, обрабатывает его.
Обратная сторона уведомляет всех, кто регистрируется на сообщение (например, шаблон Event Aggregator, обычно используемый для слабой связи ViewModels в шаблоне MVVM). Я использую следующую конструкцию
IDictionary<Type, List<Object>>
Единственный способ добавить в словарь - это функция
Register<T>(Action<T> handler)
(и объект фактически является WeakReference для переданного в обработчик). Так что здесь я должен использовать List <Object>, потому что во время компиляции я не знаю, каким будет закрытый тип. Однако во время выполнения я могу убедиться, что именно этот тип является ключевым для словаря. Когда я хочу запустить событие, я звоню
Send<T>(T message)
и снова я разрешаю список. Нет никакого преимущества в использовании List <dynamic>, потому что мне все равно нужно его привести. Итак, как вы видите, у обоих подходов есть свои достоинства. Если вы собираетесь динамически отправлять объект, используя перегрузку метода, динамический способ это сделать. Если вы вынуждены разыгрывать независимо, также можете использовать Object.