Dies ist nützlich, wenn Sie mit COM oder dynamisch typisierten Sprachen arbeiten. Wenn Sie beispielsweise lua oder python zum Erstellen von Skripten für Ihre Sprache verwenden, ist es sehr praktisch, den Skriptcode so aufzurufen, als wäre es normaler Code.
Das dynamische Schlüsselwort ist neu in C # 4.0 und wird verwendet, um dem Compiler mitzuteilen, dass sich der Typ einer Variablen ändern kann oder dass er erst zur Laufzeit bekannt ist. Stellen Sie sich vor, Sie könnten mit einem Objekt interagieren, ohne es wirken zu müssen.
dynamic cust =GetCustomer();
cust.FirstName="foo";// works as expected
cust.Process();// works as expected
cust.MissingMethod();// No method found!
Beachten Sie, dass wir cust nicht als Typ Kunde deklarieren oder deklarieren mussten. Da wir es als dynamisch deklariert haben, übernimmt die Laufzeit und sucht und legt die FirstName-Eigenschaft für uns fest. Wenn Sie jetzt eine dynamische Variable verwenden, geben Sie natürlich die Überprüfung des Compilertyps auf. Dies bedeutet, dass der Aufruf cust.MissingMethod () kompiliert wird und erst zur Laufzeit fehlschlägt. Das Ergebnis dieser Operation ist eine RuntimeBinderException, da MissingMethod in der Customer-Klasse nicht definiert ist.
Das obige Beispiel zeigt, wie dynamisch beim Aufrufen von Methoden und Eigenschaften funktioniert. Eine weitere leistungsstarke (und möglicherweise gefährliche) Funktion ist die Wiederverwendung von Variablen für verschiedene Datentypen. Ich bin mir sicher, dass die Programmierer von Python, Ruby und Perl sich eine Million Möglichkeiten vorstellen können, dies zu nutzen, aber ich habe C # so lange verwendet, dass es sich für mich einfach "falsch" anfühlt.
dynamic foo =123;
foo ="bar";
OK, Sie werden also wahrscheinlich nicht sehr oft Code wie den oben genannten schreiben. Es kann jedoch vorkommen, dass die variable Wiederverwendung nützlich sein oder einen schmutzigen Teil des Legacy-Codes bereinigen kann. Ein einfacher Fall, auf den ich oft stoße, ist das ständige Umschalten zwischen Dezimal und Doppel.
decimal foo =GetDecimalValue();
foo = foo /2.5;// Does not compile
foo =Math.Sqrt(foo);// Does not compilestring bar = foo.ToString("c");
Die zweite Zeile wird nicht kompiliert, da 2.5 als Double eingegeben wird, und Zeile 3 wird nicht kompiliert, da Math.Sqrt ein Double erwartet. Natürlich müssen Sie nur Ihren Variablentyp umwandeln und / oder ändern, aber es kann Situationen geben, in denen die Verwendung von Dynamik sinnvoll ist.
dynamic foo =GetDecimalValue();// still returns a decimal
foo = foo /2.5;// The runtime takes care of this for us
foo =Math.Sqrt(foo);// Again, the DLR works its magicstring bar = foo.ToString("c");
Persönlich mag ich den Gedanken nicht, das dynamicin c # zum Lösen von Problemen zu verwenden, die durch Standard-c # -Funktionen und statische Typisierung oder höchstens mit Typinferenz ( var) gelöst werden können (vielleicht sogar noch besser ). dynamicsollte nur verwendet werden, wenn es um Interoperabilitätsprobleme mit dem DLR geht. Wenn Sie Code in einer statisch typisierten Sprache wie c # schreiben, tun Sie dies und emulieren Sie keine dynamische Sprache. Das ist einfach hässlich.
Philip Daubmeier
40
Wenn Sie dynamicVariablen in Ihrem Code stark nutzen, wo Sie sie nicht benötigen (wie in Ihrem Beispiel mit dem Squareroot), geben Sie die Fehlerprüfung bei der Kompilierungszeit auf. Stattdessen erhalten Sie jetzt mögliche Laufzeitfehler.
Philip Daubmeier
33
Meistens in Ordnung, aber ein paar kleinere Fehler. Erstens ist es nicht richtig zu sagen, dass dynamisch bedeutet, dass sich der Variablentyp ändern kann. Die fragliche Variable ist vom Typ "dynamisch" (aus Sicht der C # -Sprache; aus Sicht der CLR ist die Variable vom Typ Objekt). Der Typ einer Variablen ändert sich nie . Der Laufzeittyp des Werts einer Variablen kann ein beliebiger Typ sein, der mit dem Typ der Variablen kompatibel ist. (Oder im Fall von Referenztypen kann es null sein.)
Eric Lippert
15
Zu Ihrem zweiten Punkt: C # hatte bereits die Funktion "Variable erstellen, in die Sie alles einfügen können" - Sie können jederzeit eine Variable vom Typ Objekt erstellen. Das Interessante an der Dynamik ist, worauf Sie in Ihrem ersten Absatz hinweisen: Die Dynamik ist nahezu identisch mit dem Objekt, mit der Ausnahme, dass die semantische Analyse bis zur Laufzeit verschoben wird und die semantische Analyse für den Laufzeittyp des Ausdrucks durchgeführt wird. (Meistens. Es gibt einige Ausnahmen.)
Eric Lippert
18
Ich habe einen Abstimmungspunkt dafür ausgegeben, hauptsächlich, weil implizit die Verwendung des Schlüsselworts für den allgemeinen Gebrauch befürwortet wird. Es hat einen spezifisch zielgerichteten Zweck (perfekt beschrieben in Lasses 'Antwort) und obwohl diese Antwort technisch korrekt ist, wird sie Entwickler wahrscheinlich in die Irre führen.
Acht-Bit-Guru
211
Das dynamicSchlüsselwort wurde zusammen mit vielen anderen neuen Funktionen von C # 4.0 hinzugefügt, um die Kommunikation mit Code zu vereinfachen, der in anderen Laufzeiten mit unterschiedlichen APIs lebt oder von diesen stammt.
Nehmen Sie ein Beispiel.
Wenn Sie ein COM-Objekt wie das Word.ApplicationObjekt haben und ein Dokument öffnen möchten, enthält die entsprechende Methode nicht weniger als 15 Parameter, von denen die meisten optional sind.
Um diese Methode aufzurufen, benötigen Sie etwa Folgendes (ich vereinfache, dies ist kein tatsächlicher Code):
Alle diese Argumente notieren? Sie müssen diese übergeben, da C # vor Version 4.0 keine Vorstellung von optionalen Argumenten hatte. In C # 4.0 wurde die Arbeit mit COM-APIs vereinfacht, indem Folgendes eingeführt wurde:
Sehen Sie, wie viel einfacher es aussieht, wie viel lesbarer es wird?
Lassen Sie uns das auseinander brechen:
named argument, can skip the rest
|
v
wordApplication.Documents.Open(@"C:\Test.docx",ReadOnly:true);^^||
notice no ref keyword, can pass
actual parameter values instead
Die Magie ist, dass der C # -Compiler jetzt den erforderlichen Code einfügt und zur Laufzeit mit neuen Klassen arbeitet, um fast genau das zu tun, was Sie zuvor getan haben, aber die Syntax wurde Ihnen verborgen, jetzt können Sie sich auf das konzentrieren was und nicht so sehr auf das wie . Anders Hejlsberg sagt gern, dass man verschiedene "Beschwörungsformeln" aufrufen muss, was eine Art Wortspiel für die Magie des Ganzen ist, bei dem man normalerweise mit den Händen winken und einige magische Wörter in der richtigen Reihenfolge sagen muss um eine bestimmte Art von Zauber in Gang zu bringen. Die alte API-Art, mit COM-Objekten zu kommunizieren, war eine Menge davon. Sie mussten durch viele Rahmen springen, um den Compiler zu überreden, den Code für Sie zu kompilieren.
In C # vor Version 4.0 wird es noch schlimmer, wenn Sie versuchen, mit einem COM-Objekt zu sprechen, für das Sie keine Schnittstelle oder Klasse haben IDispatch. Sie haben lediglich eine Referenz.
Wenn Sie nicht wissen, was es ist, IDispatchist im Grunde Reflexion für COM-Objekte. Mit einer IDispatchSchnittstelle können Sie das Objekt "Wie lautet die ID-Nummer für die als Speichern bekannte Methode?" Fragen, Arrays eines bestimmten Typs erstellen, die die Argumentwerte enthalten, und schließlich eine InvokeMethode auf der IDispatchSchnittstelle aufrufen, um die Methode aufzurufen, wobei alle übergeben werden die Informationen, die Sie zusammengetragen haben.
Die obige Speichermethode könnte folgendermaßen aussehen (dies ist definitiv nicht der richtige Code):
ist im Grunde nur C #, das VB in Bezug auf Ausdruckskraft einholt, aber es richtig macht, indem es erweiterbar gemacht wird, und nicht nur für COM. Dies ist natürlich auch für VB.NET oder eine andere Sprache verfügbar, die auf der .NET-Laufzeit basiert.
Weitere Informationen zur IDispatchBenutzeroberfläche finden Sie auf Wikipedia: IDispatch, wenn Sie mehr darüber lesen möchten. Es ist wirklich blutiges Zeug.
Was ist jedoch, wenn Sie mit einem Python-Objekt sprechen möchten? Dafür gibt es eine andere API als die für COM-Objekte verwendete. Da Python-Objekte ebenfalls dynamischer Natur sind, müssen Sie auf Reflection Magic zurückgreifen, um die richtigen Methoden zum Aufrufen, ihre Parameter usw. zu finden, nicht jedoch das .NET Reflexion, etwas, das für Python geschrieben wurde, ziemlich ähnlich dem obigen IDispatch-Code, nur ganz anders.
Und für Ruby? Noch eine andere API.
JavaScript? Gleiches Angebot, auch dafür unterschiedliche API.
Das dynamische Schlüsselwort besteht aus zwei Dingen:
Das neue Schlüsselwort in C #, dynamic
Eine Reihe von Laufzeitklassen, die wissen, wie mit den verschiedenen Objekttypen umzugehen ist, die eine bestimmte API implementieren, die für das dynamicSchlüsselwort erforderlich ist, und die Aufrufe der richtigen Vorgehensweise zuordnen. Die API ist sogar dokumentiert. Wenn Sie also Objekte haben, die aus einer nicht abgedeckten Laufzeit stammen, können Sie sie hinzufügen.
Das dynamicSchlüsselwort soll jedoch keinen vorhandenen Nur-.NET-Code ersetzen. Sicher, Sie können es tun, aber es wurde aus diesem Grund nicht hinzugefügt, und die Autoren der C # -Programmiersprache mit Anders Hejlsberg an der Spitze waren äußerst fest davon überzeugt, dass sie C # immer noch als stark typisierte Sprache betrachten und nicht opfern werden dieses Prinzip.
Dies bedeutet, dass Sie zwar Code wie folgt schreiben können:
dynamic x =10;dynamic y =3.14;dynamic z ="test";dynamic k =true;dynamic l = x + y * z - k;
und lassen Sie es kompilieren, es war nicht als eine Art magisches System gedacht, mit dem Sie herausfinden können, was Sie zur Laufzeit gemeint haben.
Der ganze Zweck war es, es einfacher zu machen, mit anderen Arten von Objekten zu sprechen.
Im Internet gibt es viel Material über das Schlüsselwort, Befürworter, Gegner, Diskussionen, Beschimpfungen, Lob usw.
Ich schlage vor, Sie beginnen mit den folgenden Links und googeln dann für mehr:
Abgesehen von COM ist es auch nützlich für Web-JSON-APIs, bei denen die Struktur der de-serialisierten JSON-Objekte in C # nicht angegeben ist. Beispielsweise gibt die Decode-Methode von System.Web.Helpers.Json ein dynamisches Objekt zurück .
Dumbledad
Abgesehen von "sie betrachten C # immer noch als eine stark typisierte Sprache": Eric Lippert ist kein Fan von "stark typisiert" als Beschreibung.
Andrew Keeton
Ich bin nicht einverstanden mit ihm, aber es ist eine Ansichtssache, keine Tatsache. "Stark typisiert" bedeutet für mich, dass der Compiler zur Kompilierungszeit weiß, welcher Typ verwendet wird, und somit die Regeln erzwingt, die für diese Typen festgelegt wurden. Die Tatsache, dass Sie sich für einen dynamischen Typ entscheiden können, der die Regelprüfung und Bindung an die Laufzeit verschiebt, bedeutet für mich nicht, dass die Sprache schwach typisiert ist. Normalerweise kontrastiere ich nicht stark mit schwach getippt, aber ich vergleiche es normalerweise mit dynamisch getippten Sprachen wie Python, in denen alles eine Ente ist, bis es bellt.
Lasse V. Karlsen
Was ist der Sinn dieser Antwort? Die Hälfte davon betrifft optionale Parameter und die IDispatch-Schnittstelle.
Xam
Aus diesem Grund dynamicwurde hinzugefügt, um andere Ökosysteme dabei zu unterstützen, wie reflexionsähnliche Methodenaufrufe durchgeführt werden können, und um eine Art Black-Box-Ansatz für Datenstrukturen bereitzustellen, mit dem dies dokumentiert werden kann.
Lasse V. Karlsen
29
Ich bin überrascht, dass niemand den Mehrfachversand erwähnt hat . Die übliche Art, dies zu umgehen , ist das Besuchermuster. Dies ist nicht immer möglich, sodass Sie gestapelte isSchecks erhalten.
Hier ist ein Beispiel aus dem wirklichen Leben für eine eigene Anwendung. Anstatt zu tun:
publicstaticMapDtoBaseCreateDto(ChartItem item){if(item isElevationPoint)returnCreateDtoImpl((ElevationPoint)item);if(item isMapPoint)returnCreateDtoImpl((MapPoint)item);if(item isMapPolyline)returnCreateDtoImpl((MapPolyline)item);//other subtypes followthrownewObjectNotFoundException("Counld not find suitable DTO for "+ item.GetType());}
Sie machen:
publicstaticMapDtoBaseCreateDto(ChartItem item){returnCreateDtoImpl(item asdynamic);}privatestaticMapDtoBaseCreateDtoImpl(ChartItem item){thrownewObjectNotFoundException("Counld not find suitable DTO for "+ item.GetType());}privatestaticMapDtoBaseCreateDtoImpl(MapPoint item){returnnewMapPointDto(item);}privatestaticMapDtoBaseCreateDtoImpl(ElevationPoint item){returnnewElevationDto(item);}
Beachten Sie, dass es sich im ersten Fall ElevationPointum eine Unterklasse von handelt MapPointund wenn es nicht platziert wird, bevorMapPoint es niemals erreicht wird. Dies ist bei Dynamic nicht der Fall, da die Methode mit der engsten Übereinstimmung aufgerufen wird.
Wie Sie dem Code entnehmen können, war diese Funktion praktisch, als ich die Übersetzung von ChartItem-Objekten in ihre serialisierbaren Versionen durchführte. Ich wollte meinen Code nicht mit Besuchern verschmutzen und ich wollte meine ChartItemObjekte auch nicht mit nutzlosen serialisierungsspezifischen Attributen verschmutzen .
Wusste nichts über diesen Anwendungsfall. Im besten Fall ein bisschen hackig. Jeder statische Analysator wird ausgeschaltet.
Kugel
2
@ Kugel das ist wahr, aber ich würde es nicht einen Hack nennen . Die statische Analyse ist gut, aber ich würde mich nicht von einer eleganten Lösung abhalten lassen, bei der die Alternativen sind: Verletzung des Open-Closed-Prinzips (Besuchermuster) oder erhöhte zyklomatische Komplexität mit gefürchteten Stapeln isübereinander.
Stelios Adamantidis
4
Nun, Sie haben die Möglichkeit, Muster mit C # 7 abzugleichen, nein?
Kugel
2
Nun, Operatoren sind auf diese Weise viel billiger (Vermeidung von Double Cast) und Sie erhalten statische Analysen zurück ;-) und Leistung.
Kugel
@idbrii bitte ändere meine Antworten nicht. Fühlen Sie sich frei, einen Kommentar zu hinterlassen, und ich werde dies (falls erforderlich) klären, da ich immer noch in dieser Community aktiv bin. Bitte auch nicht verwenden magic; Es gibt keine Magie.
Stelios Adamantidis
11
Es erleichtert statisch typisierten Sprachen (CLR) die Zusammenarbeit mit dynamischen Sprachen (Python, Ruby ...), die auf dem DLR (Dynamic Language Runtime) ausgeführt werden (siehe MSDN) :
Beispielsweise können Sie den folgenden Code verwenden, um einen Zähler in XML in C # zu erhöhen.
Und die für die Dynamik erforderliche Änderung der VM erleichtert dynamische Sprachen.
Dykam
2
@Dykam: Es gibt keine Änderung an der VM. Das DLR funktioniert bis zu .NET 2.0 einwandfrei.
Jörg W Mittag
@ Jörg, ja es gibt eine Änderung. Das DLR wird teilweise neu geschrieben, da die VM jetzt Unterstützung für dynamische Auflösung bietet.
Dykam
Ich war ein bisschen zu optimistisch, Untersuchungen haben gezeigt, dass die Veränderungen nicht so groß waren.
Dykam
4
Ein Anwendungsbeispiel:
Sie verwenden viele Klassen mit der kommunalen Eigenschaft 'CreationDate':
publicclassContact{// some propertiespublicDateTimeCreationDate{get;set;}}publicclassCompany{// some propertiespublicDateTimeCreationDate{get;set;}}publicclassOpportunity{// some propertiespublicDateTimeCreationDate{get;set;}}
Wenn Sie eine Kommunikationsmethode schreiben, die den Wert der Eigenschaft 'CreationDate' abruft, müssen Sie Reflection verwenden:
Es wird hauptsächlich von RAD- und Python-Opfern verwendet, um die Codequalität, IntelliSense und die Fehlererkennung bei der Kompilierung zu zerstören .
Eine zynische Antwort, aber leicht zu wahr. Ich habe es einfach getan, um zu vermeiden, dass Strukturen deklariert werden, mit dem Ergebnis, dass der Code funktioniert, wenn alles in Ordnung ist, aber seinen Stapel auf unvorhersehbare Weise aufbläst, sobald Sie den Käse verschieben.
AnthonyVO
Ja, Sie werden diesen klassischen Eckschnitt mit vielen anderen Sprachfunktionen sehen. Es ist keine Überraschung, dass Sie es auch hier sehen würden.
Hawkeye4040
1
Es wird zur Laufzeit ausgewertet, sodass Sie den Typ wie in JavaScript nach Belieben ändern können. Das ist echt:
dynamic i =12;
i ="text";
Und so können Sie den Typ nach Bedarf ändern. Verwenden Sie es als letzten Ausweg; Es ist von Vorteil, aber ich habe gehört, dass in Bezug auf die generierte IL unter den Kulissen viel passiert, und das kann zu einem Leistungspreis führen.
Ich würde zögern zu sagen, dass es "legitim" ist. Es wird sicherlich kompiliert, so dass es als solches "legitimer Code" in dem Sinne ist, dass der Compiler es jetzt kompiliert und die Laufzeit es ausführt. Aber ich würde niemals diesen bestimmten Code (oder etwas Ähnliches) in einem der von mir gepflegten Codes sehen wollen, oder es wäre eine beinahe feuernde Straftat.
Lasse V. Karlsen
6
Sicher, aber das wäre "legitim" mit "Objekt" statt "dynamisch" gewesen. Sie haben hier nichts Interessantes über Dynamik gezeigt.
Eric Lippert
Für ein Objekt müssten Sie es in den entsprechenden Typ umwandeln, um tatsächlich eine seiner Methoden aufzurufen ... Sie verlieren die Signatur; Sie können Ihren Code jede Methode aufrufen lassen, ohne dass ein Kompilierungsfehler auftritt, und dieser Fehler tritt zur Laufzeit auf. Ich hatte es eilig, etwas zu tippen. Und @Lasse, ich würde zustimmen und ich werde wahrscheinlich nicht viel Dynamik verwenden.
Brian Mains
1
Der Anwendungsfall des letzten
Auswegs
1
Der beste Anwendungsfall für Variablen vom Typ 'dynamisch' war für mich, als ich kürzlich eine Datenzugriffsschicht in ADO.NET ( mit SQLDataReader ) schrieb und der Code die bereits geschriebenen gespeicherten Legacy-Prozeduren aufrief . Es gibt Hunderte dieser alten gespeicherten Prozeduren, die einen Großteil der Geschäftslogik enthalten. Meine Datenzugriffsschicht musste eine Art strukturierter Daten an die C # -basierte Geschäftslogikschicht zurückgeben, um einige Manipulationen durchzuführen ( obwohl es fast keine gibt ). Jede gespeicherte Prozedur gibt einen anderen Datensatz zurück ( Tabellenspalten ). Anstatt Dutzende von Klassen oder Strukturen zu erstellen, um die zurückgegebenen Daten zu speichern und an die BLL zu übergeben, habe ich den folgenden Code geschrieben, der recht elegant und ordentlich aussieht.
publicstaticdynamicGetSomeData(ParameterDTO dto){dynamic result =null;stringSPName="a_legacy_stored_procedure";
using (SqlConnection connection =newSqlConnection(DataConnection.ConnectionString)){SqlCommand command =newSqlCommand(SPName, connection);
command.CommandType=System.Data.CommandType.StoredProcedure;
command.Parameters.Add(newSqlParameter("@empid", dto.EmpID));
command.Parameters.Add(newSqlParameter("@deptid", dto.DeptID));
connection.Open();
using (SqlDataReader reader = command.ExecuteReader()){while(reader.Read()){dynamic row =newExpandoObject();
row.EmpName= reader["EmpFullName"].ToString();
row.DeptName= reader["DeptName"].ToString();
row.AnotherColumn= reader["AnotherColumn"].ToString();
result = row;}}}return result;}
Sie können mit Pythonnet in dynamische Sprachen wie CPython aufrufen:
dynamic np = Py.Import("numpy")
Sie können Generika umwandeln, dynamicwenn Sie numerische Operatoren auf sie anwenden. Dies bietet Typensicherheit und vermeidet Einschränkungen von Generika. Dies ist im Wesentlichen * Ententypisierung:
Ein weiterer Anwendungsfall für die dynamicEingabe sind virtuelle Methoden, bei denen ein Problem mit Kovarianz oder Kontravarianz auftritt. Ein solches Beispiel ist die berüchtigte CloneMethode, die ein Objekt des gleichen Typs wie das Objekt zurückgibt, für das es aufgerufen wird. Dieses Problem wird mit einer dynamischen Rückgabe nicht vollständig gelöst, da die statische Typprüfung umgangen wird. Zumindest müssen Sie bei der Verwendung von Plain nicht immer hässliche Casts verwenden object. Ansonsten werden die Casts implizit.
publicclass A
{// attributes and constructor herepublicvirtualdynamicClone(){var clone =new A();// Do more cloning stuff herereturn clone;}}publicclass B : A
{// more attributes and constructor herepublicoverridedynamicClone(){var clone =new B();// Do more cloning stuff herereturn clone;}}publicclassProgram{publicstaticvoidMain(){
A a =new A().Clone();// No cast needed here
B b =new B().Clone();// and here// do more stuff with a and b}}
Antworten:
Das dynamische Schlüsselwort ist neu in C # 4.0 und wird verwendet, um dem Compiler mitzuteilen, dass sich der Typ einer Variablen ändern kann oder dass er erst zur Laufzeit bekannt ist. Stellen Sie sich vor, Sie könnten mit einem Objekt interagieren, ohne es wirken zu müssen.
Beachten Sie, dass wir cust nicht als Typ Kunde deklarieren oder deklarieren mussten. Da wir es als dynamisch deklariert haben, übernimmt die Laufzeit und sucht und legt die FirstName-Eigenschaft für uns fest. Wenn Sie jetzt eine dynamische Variable verwenden, geben Sie natürlich die Überprüfung des Compilertyps auf. Dies bedeutet, dass der Aufruf cust.MissingMethod () kompiliert wird und erst zur Laufzeit fehlschlägt. Das Ergebnis dieser Operation ist eine RuntimeBinderException, da MissingMethod in der Customer-Klasse nicht definiert ist.
Das obige Beispiel zeigt, wie dynamisch beim Aufrufen von Methoden und Eigenschaften funktioniert. Eine weitere leistungsstarke (und möglicherweise gefährliche) Funktion ist die Wiederverwendung von Variablen für verschiedene Datentypen. Ich bin mir sicher, dass die Programmierer von Python, Ruby und Perl sich eine Million Möglichkeiten vorstellen können, dies zu nutzen, aber ich habe C # so lange verwendet, dass es sich für mich einfach "falsch" anfühlt.
OK, Sie werden also wahrscheinlich nicht sehr oft Code wie den oben genannten schreiben. Es kann jedoch vorkommen, dass die variable Wiederverwendung nützlich sein oder einen schmutzigen Teil des Legacy-Codes bereinigen kann. Ein einfacher Fall, auf den ich oft stoße, ist das ständige Umschalten zwischen Dezimal und Doppel.
Die zweite Zeile wird nicht kompiliert, da 2.5 als Double eingegeben wird, und Zeile 3 wird nicht kompiliert, da Math.Sqrt ein Double erwartet. Natürlich müssen Sie nur Ihren Variablentyp umwandeln und / oder ändern, aber es kann Situationen geben, in denen die Verwendung von Dynamik sinnvoll ist.
Weitere Informationen finden Sie unter: http://www.codeproject.com/KB/cs/CSharp4Features.aspx
quelle
dynamic
in c # zum Lösen von Problemen zu verwenden, die durch Standard-c # -Funktionen und statische Typisierung oder höchstens mit Typinferenz (var
) gelöst werden können (vielleicht sogar noch besser ).dynamic
sollte nur verwendet werden, wenn es um Interoperabilitätsprobleme mit dem DLR geht. Wenn Sie Code in einer statisch typisierten Sprache wie c # schreiben, tun Sie dies und emulieren Sie keine dynamische Sprache. Das ist einfach hässlich.dynamic
Variablen in Ihrem Code stark nutzen, wo Sie sie nicht benötigen (wie in Ihrem Beispiel mit dem Squareroot), geben Sie die Fehlerprüfung bei der Kompilierungszeit auf. Stattdessen erhalten Sie jetzt mögliche Laufzeitfehler.Das
dynamic
Schlüsselwort wurde zusammen mit vielen anderen neuen Funktionen von C # 4.0 hinzugefügt, um die Kommunikation mit Code zu vereinfachen, der in anderen Laufzeiten mit unterschiedlichen APIs lebt oder von diesen stammt.Nehmen Sie ein Beispiel.
Wenn Sie ein COM-Objekt wie das
Word.Application
Objekt haben und ein Dokument öffnen möchten, enthält die entsprechende Methode nicht weniger als 15 Parameter, von denen die meisten optional sind.Um diese Methode aufzurufen, benötigen Sie etwa Folgendes (ich vereinfache, dies ist kein tatsächlicher Code):
Alle diese Argumente notieren? Sie müssen diese übergeben, da C # vor Version 4.0 keine Vorstellung von optionalen Argumenten hatte. In C # 4.0 wurde die Arbeit mit COM-APIs vereinfacht, indem Folgendes eingeführt wurde:
ref
optional für COM - APIsDie neue Syntax für den obigen Aufruf wäre:
Sehen Sie, wie viel einfacher es aussieht, wie viel lesbarer es wird?
Lassen Sie uns das auseinander brechen:
Die Magie ist, dass der C # -Compiler jetzt den erforderlichen Code einfügt und zur Laufzeit mit neuen Klassen arbeitet, um fast genau das zu tun, was Sie zuvor getan haben, aber die Syntax wurde Ihnen verborgen, jetzt können Sie sich auf das konzentrieren was und nicht so sehr auf das wie . Anders Hejlsberg sagt gern, dass man verschiedene "Beschwörungsformeln" aufrufen muss, was eine Art Wortspiel für die Magie des Ganzen ist, bei dem man normalerweise mit den Händen winken und einige magische Wörter in der richtigen Reihenfolge sagen muss um eine bestimmte Art von Zauber in Gang zu bringen. Die alte API-Art, mit COM-Objekten zu kommunizieren, war eine Menge davon. Sie mussten durch viele Rahmen springen, um den Compiler zu überreden, den Code für Sie zu kompilieren.
In C # vor Version 4.0 wird es noch schlimmer, wenn Sie versuchen, mit einem COM-Objekt zu sprechen, für das Sie keine Schnittstelle oder Klasse haben
IDispatch
. Sie haben lediglich eine Referenz.Wenn Sie nicht wissen, was es ist,
IDispatch
ist im Grunde Reflexion für COM-Objekte. Mit einerIDispatch
Schnittstelle können Sie das Objekt "Wie lautet die ID-Nummer für die als Speichern bekannte Methode?" Fragen, Arrays eines bestimmten Typs erstellen, die die Argumentwerte enthalten, und schließlich eineInvoke
Methode auf derIDispatch
Schnittstelle aufrufen, um die Methode aufzurufen, wobei alle übergeben werden die Informationen, die Sie zusammengetragen haben.Die obige Speichermethode könnte folgendermaßen aussehen (dies ist definitiv nicht der richtige Code):
All dies, um nur ein Dokument zu öffnen.
VB hatte vor langer Zeit optionale Argumente und Unterstützung für das meiste davon, also diesen C # -Code:
ist im Grunde nur C #, das VB in Bezug auf Ausdruckskraft einholt, aber es richtig macht, indem es erweiterbar gemacht wird, und nicht nur für COM. Dies ist natürlich auch für VB.NET oder eine andere Sprache verfügbar, die auf der .NET-Laufzeit basiert.
Weitere Informationen zur
IDispatch
Benutzeroberfläche finden Sie auf Wikipedia: IDispatch, wenn Sie mehr darüber lesen möchten. Es ist wirklich blutiges Zeug.Was ist jedoch, wenn Sie mit einem Python-Objekt sprechen möchten? Dafür gibt es eine andere API als die für COM-Objekte verwendete. Da Python-Objekte ebenfalls dynamischer Natur sind, müssen Sie auf Reflection Magic zurückgreifen, um die richtigen Methoden zum Aufrufen, ihre Parameter usw. zu finden, nicht jedoch das .NET Reflexion, etwas, das für Python geschrieben wurde, ziemlich ähnlich dem obigen IDispatch-Code, nur ganz anders.
Und für Ruby? Noch eine andere API.
JavaScript? Gleiches Angebot, auch dafür unterschiedliche API.
Das dynamische Schlüsselwort besteht aus zwei Dingen:
dynamic
dynamic
Schlüsselwort erforderlich ist, und die Aufrufe der richtigen Vorgehensweise zuordnen. Die API ist sogar dokumentiert. Wenn Sie also Objekte haben, die aus einer nicht abgedeckten Laufzeit stammen, können Sie sie hinzufügen.Das
dynamic
Schlüsselwort soll jedoch keinen vorhandenen Nur-.NET-Code ersetzen. Sicher, Sie können es tun, aber es wurde aus diesem Grund nicht hinzugefügt, und die Autoren der C # -Programmiersprache mit Anders Hejlsberg an der Spitze waren äußerst fest davon überzeugt, dass sie C # immer noch als stark typisierte Sprache betrachten und nicht opfern werden dieses Prinzip.Dies bedeutet, dass Sie zwar Code wie folgt schreiben können:
und lassen Sie es kompilieren, es war nicht als eine Art magisches System gedacht, mit dem Sie herausfinden können, was Sie zur Laufzeit gemeint haben.
Der ganze Zweck war es, es einfacher zu machen, mit anderen Arten von Objekten zu sprechen.
Im Internet gibt es viel Material über das Schlüsselwort, Befürworter, Gegner, Diskussionen, Beschimpfungen, Lob usw.
Ich schlage vor, Sie beginnen mit den folgenden Links und googeln dann für mehr:
quelle
dynamic
wurde hinzugefügt, um andere Ökosysteme dabei zu unterstützen, wie reflexionsähnliche Methodenaufrufe durchgeführt werden können, und um eine Art Black-Box-Ansatz für Datenstrukturen bereitzustellen, mit dem dies dokumentiert werden kann.Ich bin überrascht, dass niemand den Mehrfachversand erwähnt hat . Die übliche Art, dies zu umgehen , ist das Besuchermuster. Dies ist nicht immer möglich, sodass Sie gestapelte
is
Schecks erhalten.Hier ist ein Beispiel aus dem wirklichen Leben für eine eigene Anwendung. Anstatt zu tun:
Sie machen:
Beachten Sie, dass es sich im ersten Fall
ElevationPoint
um eine Unterklasse von handeltMapPoint
und wenn es nicht platziert wird, bevorMapPoint
es niemals erreicht wird. Dies ist bei Dynamic nicht der Fall, da die Methode mit der engsten Übereinstimmung aufgerufen wird.Wie Sie dem Code entnehmen können, war diese Funktion praktisch, als ich die Übersetzung von ChartItem-Objekten in ihre serialisierbaren Versionen durchführte. Ich wollte meinen Code nicht mit Besuchern verschmutzen und ich wollte meine
ChartItem
Objekte auch nicht mit nutzlosen serialisierungsspezifischen Attributen verschmutzen .quelle
is
übereinander.magic
; Es gibt keine Magie.Es erleichtert statisch typisierten Sprachen (CLR) die Zusammenarbeit mit dynamischen Sprachen (Python, Ruby ...), die auf dem DLR (Dynamic Language Runtime) ausgeführt werden (siehe MSDN) :
MSDN listet diese Vorteile auf:
Weitere Informationen finden Sie unter MSDN .
quelle
Ein Anwendungsbeispiel:
Sie verwenden viele Klassen mit der kommunalen Eigenschaft 'CreationDate':
Wenn Sie eine Kommunikationsmethode schreiben, die den Wert der Eigenschaft 'CreationDate' abruft, müssen Sie Reflection verwenden:
Mit dem "dynamischen" Konzept ist Ihr Code viel eleganter:
quelle
COM interop. Besonders unbekannt. Es wurde speziell dafür entwickelt.
quelle
Es wird hauptsächlich von RAD- und Python-Opfern verwendet, um die Codequalität, IntelliSense und die Fehlererkennung bei der Kompilierung zu zerstören .
quelle
Es wird zur Laufzeit ausgewertet, sodass Sie den Typ wie in JavaScript nach Belieben ändern können. Das ist echt:
Und so können Sie den Typ nach Bedarf ändern. Verwenden Sie es als letzten Ausweg; Es ist von Vorteil, aber ich habe gehört, dass in Bezug auf die generierte IL unter den Kulissen viel passiert, und das kann zu einem Leistungspreis führen.
quelle
Der beste Anwendungsfall für Variablen vom Typ 'dynamisch' war für mich, als ich kürzlich eine Datenzugriffsschicht in ADO.NET ( mit SQLDataReader ) schrieb und der Code die bereits geschriebenen gespeicherten Legacy-Prozeduren aufrief . Es gibt Hunderte dieser alten gespeicherten Prozeduren, die einen Großteil der Geschäftslogik enthalten. Meine Datenzugriffsschicht musste eine Art strukturierter Daten an die C # -basierte Geschäftslogikschicht zurückgeben, um einige Manipulationen durchzuführen ( obwohl es fast keine gibt ). Jede gespeicherte Prozedur gibt einen anderen Datensatz zurück ( Tabellenspalten ). Anstatt Dutzende von Klassen oder Strukturen zu erstellen, um die zurückgegebenen Daten zu speichern und an die BLL zu übergeben, habe ich den folgenden Code geschrieben, der recht elegant und ordentlich aussieht.
quelle
dynamic np = Py.Import("numpy")
dynamic
wenn Sie numerische Operatoren auf sie anwenden. Dies bietet Typensicherheit und vermeidet Einschränkungen von Generika. Dies ist im Wesentlichen * Ententypisierung:T y = x * (dynamic)x
, wotypeof(x) is T
quelle
Ein weiterer Anwendungsfall für die
dynamic
Eingabe sind virtuelle Methoden, bei denen ein Problem mit Kovarianz oder Kontravarianz auftritt. Ein solches Beispiel ist die berüchtigteClone
Methode, die ein Objekt des gleichen Typs wie das Objekt zurückgibt, für das es aufgerufen wird. Dieses Problem wird mit einer dynamischen Rückgabe nicht vollständig gelöst, da die statische Typprüfung umgangen wird. Zumindest müssen Sie bei der Verwendung von Plain nicht immer hässliche Casts verwendenobject
. Ansonsten werden die Casts implizit.quelle