W językach funkcjonalnych (takich jak lisp) używasz dopasowania wzorca, aby określić, co dzieje się z określonym elementem na liście. Odpowiednikiem w języku C # byłby łańcuch instrukcji if ... elseif, które sprawdzają typ elementu i wykonują na tej podstawie operację. Nie trzeba dodawać, że funkcjonalne dopasowanie wzorca jest bardziej wydajne niż sprawdzanie typu środowiska wykonawczego.
Zastosowanie polimorfizmu byłoby bliższe dopasowaniu do dopasowania wzorca. Oznacza to, że dopasowanie obiektów listy do określonego interfejsu i wywołanie funkcji w tym interfejsie dla każdego obiektu. Inną alternatywą byłoby zapewnienie serii przeciążonych metod, które przyjmują określony typ obiektu jako parametr. Domyślna metoda przyjmująca Object jako parametr.
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
}
}
Takie podejście zapewnia przybliżenie dopasowania wzorca Lisp. Wzorzec odwiedzających (jak tu zaimplementowano, jest doskonałym przykładem użycia list heterogenicznych). Innym przykładem może być wysyłanie wiadomości, w której są nasłuchiwania określonych wiadomości w kolejce priorytetowej i przy użyciu łańcucha odpowiedzialności, dyspozytor przekazuje wiadomość, a pierwszy moduł obsługi, który pasuje do wiadomości, obsługuje ją.
Odwrotna strona powiadamia wszystkich, którzy zarejestrują się na wiadomość (na przykład wzorzec agregatora zdarzeń powszechnie używany do luźnego łączenia ViewModels we wzorcu MVVM). Używam następującej konstrukcji
IDictionary<Type, List<Object>>
Jedynym sposobem na dodanie do słownika jest funkcja
Register<T>(Action<T> handler)
(a obiekt jest w rzeczywistości słabym odniesieniem do przekazywanego programu obsługi). Więc muszę użyć List <Object>, ponieważ w czasie kompilacji nie wiem, jaki będzie typ zamknięty. Jednak w Runtime mogę wymusić, że to ten typ jest kluczem do słownika. Kiedy chcę odpalić wydarzenie, wzywam
Send<T>(T message)
i ponownie rozwiązuję listę. Nie ma żadnej korzyści z używania Listy <dynamicznej>, ponieważ i tak muszę ją rzucić. Jak widać, zalety obu podejść są zasadne. Jeśli zamierzasz dynamicznie wywołać obiekt za pomocą przeciążenia metody, dynamika jest na to sposobem. Jeśli jesteś zmuszony do rzucania niezależnie, równie dobrze możesz użyć Object.