Dies ist der letzte Teil der
Dynamic Language Runtime- Reihe. Vorherige Artikel:
- Dynamisches Detail: Undercover-Spiele des Compilers, Speicherverlust, Leistungsnuancen . Dieser Artikel beschreibt den DLR-Cache im Detail und die Punkte, die für den Entwickler wichtig sind.
- Grokl DLR . Ein allgemeiner Überblick über die Technologie, die Analyse von DynamicMetaObject und eine kurze Anleitung zum Erstellen Ihrer eigenen dynamischen Klasse.
In diesem kurzen Artikel werden wir schließlich die Hauptfälle der Verwendung von
Dynamik im wirklichen Leben analysieren: Wenn Sie nicht darauf verzichten können und wenn dies die Existenz erheblich erleichtern kann.

Wenn Dynamik unverzichtbar ist
Es gibt keine solchen Fälle. Sie können immer Code mit ähnlicher Funktionalität in einem statischen Stil schreiben. Der einzige Unterschied besteht in der einfachen Lesbarkeit und der Codemenge. Wenn Sie beispielsweise mit COM-Objekten anstatt mit
dynamischen Objekten arbeiten, können Sie die Reflektion verwenden.
Wenn Dynamik nützlich ist
Arbeiten Sie mit COM-Objekten
Zuallererst ist dies natürlich die Arbeit mit COM-Objekten, für die all dies gestartet wurde. Vergleichen Sie den erhaltenen Code mit
Dynamik und Reflexion:
dynamic instance = Activator.CreateInstance(type); instance.Run("Notepad.exe");
var instance = Activator.CreateInstance(type); type.InvokeMember("Run", BindingFlags.InvokeMethod, null, instance, new[] { "Notepad.exe" });
Um mit COM-Objekten durch Reflektion zu arbeiten, müssen Sie in der Regel Verzweigungsklassen mit Wrappern für jede Methode / Eigenschaft erstellen. Es gibt auch weniger offensichtliche Vorteile, wie die Möglichkeit, nicht benötigte Parameter nicht einzugeben (obligatorisch aus Sicht eines COM-Objekts), wenn eine Methode über
dynamic aufgerufen wird .
Arbeite mit Konfigurationen
Ein weiteres Lehrbuchbeispiel ist die Arbeit mit Konfigurationen wie
XML . Ohne
Dynamik :
XElement person = XElement.Parse(xml); Console.WriteLine( $"{person.Descendants("FirstName").FirstOrDefault().Value} {person.Descendants("LastName").FirstOrDefault().Value}" );
Mit Dynamik:
dynamic person = DynamicXml.Parse(xml); Console.WriteLine( $"{person.FirstName} {person.LastName}" );
Dazu müssen Sie natürlich Ihre eigene dynamische Klasse implementieren. Alternativ zur ersten Auflistung können Sie eine Klasse schreiben, die ungefähr so funktioniert:
var person = StaticXml.Parse(xml); Console.WriteLine( $"{person.GetElement("FirstName")} {person.GetElement("LastName")}" );
Aber Sie sehen, das sieht viel weniger elegant aus als durch
Dynamik .
Arbeiten Sie mit externen Ressourcen
Der vorherige Absatz kann auf alle Aktionen mit externen Ressourcen verallgemeinert werden. Wir haben immer zwei Alternativen: Verwenden von
Dynamic , um den Code im nativen C # -Stil abzurufen, oder statische Eingabe mit „magischen Linien“. Schauen wir uns ein Beispiel mit einer
REST-API- Anforderung an. Mit dynamic können Sie Folgendes schreiben:
dynamic dynamicRestApiClient = new DynamicRestApiClient("http://localhost:18457/api"); dynamic catsList = dynamicRestApiClient.CatsList;
Wo unsere dynamische Klasse eine Anfrage des Formulars auf Anfrage der Eigenschaft sendet
[GET] http://localhost:18457/api/catslist
Dann deserialisiert er es und gibt uns eine Reihe von Katzen zurück, die bereits für den beabsichtigten Gebrauch bereit sind. Ohne
Dynamik würde es ungefähr so aussehen:
var restApiClient = new RestApiClient("http://localhost:18457/api"); var catsListJson = restApiClient.Get("catsList"); var deserializedCatsList = JsonConvert.DeserializeObject<Cat[]>(catsListJson);
Reflexionsersatz
Im vorherigen Beispiel haben Sie möglicherweise eine Frage: Warum deserialisieren wir in einem Fall den Rückgabewert auf einen bestimmten Typ und im anderen nicht? Tatsache ist, dass wir bei der statischen Typisierung Objekte explizit in den
Cat- Typ umwandeln müssen, um mit ihnen arbeiten zu können. Im Fall von
Dynamik reicht es aus,
JSON in ein Array von Objekten innerhalb unserer dynamischen Klasse zu deserialisieren und
Objekt [] daraus zurückzugeben, da sich
dynamisch um die Reflexion kümmert. Ich werde zwei Beispiele geben, wie dies funktioniert:
dynamic deserialized = JsonConvert.DeserializeObject<object>(serialized); var name = deserialized.Name; var lastName = deserialized.LastName;
Attribute[] attributes = type.GetCustomAttributes(false).OfType<Attribute>(); dynamic attribute = attributes.Single(x => x.GetType().Name == "DescriptionAttribute"); var description = attribute.Description;
Das gleiche Prinzip wie bei der Arbeit mit COM-Objekten.
Besucher
Mit
Dynamic können Sie dieses Muster sehr elegant implementieren. Anstelle von tausend Worten:
public static void DoSomeWork(Item item) { InternalDoSomeWork((dynamic) item); } private static void InternalDoSomeWork(Item item) { throw new Exception("Couldn't find handler for " + item.GetType()); } private static void InternalDoSomeWork(Sword item) {
Wenn Sie nun ein Objekt vom Typ
Sword an die
DoSomeWork- Methode übergeben, wird die
InternalDoSomeWork- Methode
(Sword item) aufgerufen.
Schlussfolgerungen
Vorteile der Verwendung von
Dynamic :
- Kann für Rapid Prototyping verwendet werden: In den meisten Fällen nimmt die Anzahl der Boilerplate-Codes ab
- In der Regel verbessert es die Lesbarkeit und Ästhetik (aufgrund des Übergangs von „magischen Linien“ zum nativen Stil der Sprache) des Codes
- Trotz der weit verbreiteten Meinung entsteht dank Caching-Mechanismen im allgemeinen Fall kein erheblicher Leistungsaufwand
Nachteile der Verwendung von dynamischen:
- Es gibt nicht offensichtliche Nuancen, die mit Gedächtnis und Leistung verbunden sind.
- Mit der Unterstützung und dem Lesen solcher dynamischer Klassen müssen Sie gut verstehen, was los ist
- Dem Programmierer werden die Typprüfung und alle vom Compiler bereitgestellten Integritätsgarantien entzogen
Fazit
Meiner Meinung nach wird der Entwickler den größten Gewinn aus der Verwendung von Dynamic in den folgenden Situationen ziehen:
- Beim Prototyping
- In kleinen / privaten Projekten, in denen die Fehlerkosten niedrig sind
- In kleinen Dienstprogrammen mit Codegröße, die keine lange Laufzeit bedeuten. Wenn Ihr Dienstprogramm im schlimmsten Fall einige Sekunden lang ausgeführt wird, müssen Sie normalerweise nicht über Speicherverluste und Leistungseinbußen nachdenken
Zumindest umstritten ist die Verwendung von
Dynamik in komplexen Projekten mit einer großen Codebasis - hier ist es besser, Zeit damit zu verbringen, statische Wrapper zu schreiben, um so die Anzahl nicht offensichtlicher Momente zu minimieren.
Wenn Sie mit COM-Objekten oder -Domänen in Diensten / Produkten arbeiten, die eine lange ununterbrochene Arbeitszeit erfordern, ist es besser, keine
Dynamik zu verwenden, obwohl sie für solche Fälle erstellt wurde. Selbst wenn Sie genau wissen, was und wie zu tun ist und niemals Fehler machen, kann früher oder später ein neuer Entwickler kommen, der dies nicht weiß. Das Ergebnis ist wahrscheinlich ein schwer zu berechnender Speicherverlust.