Dynamisch in C #: Verwendungsrezepte

Dies ist der letzte Teil der Dynamic Language Runtime- Reihe. Vorherige Artikel:

  1. 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.
  2. 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) { //do some work with sword } private static void InternalDoSomeWork(Shield item) { //do some work with shield } public class Item { } public class Sword : Item {} public class Shield : 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.

Source: https://habr.com/ru/post/de470355/


All Articles