Nei linguaggi funzionali (come il lisp), si usa la corrispondenza del modello per determinare cosa succede a un particolare elemento in una lista. L'equivalente in C # sarebbe una catena di if ... elseif che controllano il tipo di un elemento ed eseguono un'operazione basata su questo. Inutile dire che la corrispondenza dei modelli funzionali è più efficiente del controllo del tipo di runtime.
Usare il polimorfismo sarebbe una corrispondenza più stretta con la corrispondenza del modello. Cioè, avere gli oggetti di una lista abbinare una particolare interfaccia e chiamare una funzione su quella interfaccia per ogni oggetto. Un'altra alternativa sarebbe quella di fornire una serie di metodi sovraccaricati che accettano un tipo di oggetto specifico come parametro. Il metodo predefinito che accetta Object come parametro.
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
}
}
Questo approccio fornisce un'approssimazione alla corrispondenza del modello Lisp. Il modello di visitatore (come implementato qui, è un ottimo esempio di utilizzo per elenchi eterogenei). Un altro esempio potrebbe essere l'invio di messaggi dove, ci sono ascoltatori per determinati messaggi in una coda di priorità e utilizzando la catena di responsabilità, il dispatcher passa il messaggio e il primo gestore che corrisponde al messaggio lo gestisce.
Il rovescio della medaglia è la notifica a tutti coloro che registrano un messaggio (ad esempio il pattern Aggregatore eventi comunemente usato per l'accoppiamento lento di ViewModels nel pattern MVVM). Io uso il seguente costrutto
IDictionary<Type, List<Object>>
L'unico modo per aggiungere al dizionario è una funzione
Register<T>(Action<T> handler)
(e l'oggetto è in realtà un WeakReference per il gestore in ingresso passato). Quindi qui DEVO usare List < Object > perché al momento della compilazione, non so quale sarà il tipo chiuso. In fase di esecuzione, tuttavia, posso far sì che sarà quel tipo che è la chiave per il dizionario. Quando voglio attivare l'evento che chiamo
Send<T>(T message)
e di nuovo risolvo la lista. Non c'è alcun vantaggio nell'uso di List < dynamic > perché ho bisogno di lanciarlo comunque. Quindi, come vedi, ci sono meriti per entrambi gli approcci. Se invii in modo dinamico un oggetto utilizzando l'overloading del metodo, dinamico è il modo per farlo. Se sei FORCATO a cast a prescindere, potresti usare Object.