In funktionalen Sprachen (wie lisp) verwenden Sie den Mustervergleich, um zu bestimmen, was mit einem bestimmten Element in einer Liste geschieht. Das Äquivalent in C # wäre eine Kette von if ... elseif-Anweisungen, die den Typ eines Elements prüfen und eine darauf basierende Operation ausführen. Es erübrigt sich zu erwähnen, dass der funktionale Mustervergleich effizienter ist als die Überprüfung des Laufzeit-Typs.
Die Verwendung von Polymorphismus wäre eine engere Übereinstimmung mit der Musterübereinstimmung. Das heißt, die Objekte einer Liste stimmen mit einer bestimmten Schnittstelle überein, und für jedes Objekt wird eine Funktion für diese Schnittstelle aufgerufen. Eine andere Alternative wäre die Bereitstellung einer Reihe überladener Methoden, die einen bestimmten Objekttyp als Parameter verwenden. Die Standardmethode, die Object als Parameter verwendet.
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
}
}
Dieser Ansatz liefert eine Annäherung an den Lisp-Musterabgleich. Das Besuchermuster (wie hier implementiert, ist ein großartiges Anwendungsbeispiel für heterogene Listen). Ein weiteres Beispiel wäre das Versenden von Nachrichten, bei dem sich Listener für bestimmte Nachrichten in einer Prioritätswarteschlange befinden und die Verantwortungskette verwendet wird. Der Dispatcher übergibt die Nachricht und der erste Handler, der mit der Nachricht übereinstimmt, verarbeitet sie.
Die Kehrseite benachrichtigt alle, die sich für eine Nachricht registrieren (z. B. das Ereignisaggregatormuster, das häufig für die lose Kopplung von ViewModels im MVVM-Muster verwendet wird). Ich benutze das folgende Konstrukt
IDictionary<Type, List<Object>>
Die einzige Möglichkeit, dem Wörterbuch etwas hinzuzufügen, ist eine Funktion
Register<T>(Action<T> handler)
(und das Objekt ist eigentlich eine WeakReference zum übergebenen Handler). Hier MUSS ich also List <Object> verwenden, da ich zur Kompilierungszeit nicht weiß, wie der geschlossene Typ aussehen wird. Zur Laufzeit kann ich jedoch erzwingen, dass es der Typ ist, der den Schlüssel für das Wörterbuch darstellt. Wenn ich das Ereignis auslösen möchte, rufe ich an
Send<T>(T message)
und wieder löse ich die liste auf. Die Verwendung von List <dynamic> bietet keinen Vorteil, da ich sie ohnehin umsetzen muss. Wie Sie sehen, haben beide Ansätze ihre Vorzüge. Wenn Sie ein Objekt mithilfe der Methode "Überladen" dynamisch versenden möchten, können Sie dies mithilfe der Methode "Dynamisch" tun. Wenn Sie trotzdem gezwungen sind, zu zaubern, können Sie auch Object verwenden.