Antworten:
Das dynamic
Schlüsselwort wird verwendet, um Variablen zu deklarieren, die spät gebunden werden sollen.
Wenn Sie eine späte Bindung für einen realen oder imaginären Typ verwenden möchten, verwenden Sie diedynamic
Schlüsselwort und der Compiler erledigt den Rest.
Wenn Sie das dynamic
Schlüsselwort verwenden, um mit einer normalen Instanz, dem DLR, zu interagieren spät gebundene Aufrufe der normalen Methoden der Instanz durch.
Die IDynamicMetaObjectProvider
Schnittstelle ermöglicht es einer Klasse, die Kontrolle über ihr spät gebundenes Verhalten zu übernehmen.
Wenn Sie das dynamic
Schlüsselwort für die Interaktion mit einer IDynamicMetaObjectProvider
Implementierung verwenden, ruft das DLR die IDynamicMetaObjectProvider
Methoden auf und das Objekt selbst entscheidet, was zu tun ist.
Die ExpandoObject
und DynamicObject
Klassen sind Implementierungen von IDynamicMetaObjectProvider
.
ExpandoObject
ist eine einfache Klasse, mit der Sie Mitglieder zu einer Instanz hinzufügen und sie als dynamic
Verbündeten verwenden können .
DynamicObject
ist eine erweiterte Implementierung, die vererbt werden kann, um auf einfache Weise ein benutzerdefiniertes Verhalten bereitzustellen.
Ich werde versuchen, eine klarere Antwort auf diese Frage zu geben, um klar zu erklären, was die Unterschiede zwischen dynamisch ExpandoObject
und sindDynamicObject
.
Sehr schnell dynamic
ist ein Schlüsselwort. Es ist kein Typ an sich. Es ist ein Schlüsselwort, das den Compiler anweist, die statische Typprüfung zur Entwurfszeit zu ignorieren und stattdessen zur Laufzeit die späte Bindung zu verwenden. Wir werden also dynamic
im Rest dieser Antwort nicht viel Zeit damit verbringen .
ExpandoObject
und DynamicObject
sind in der Tat Typen. Auf der OBERFLÄCHE sehen sie einander sehr ähnlich. Beide Klassen implementieren IDynamicMetaObjectProvider
. Wenn Sie jedoch tiefer graben, werden Sie feststellen, dass sie sich überhaupt nicht ähneln.
DynamicObject ist eine Teilimplementierung, die IDynamicMetaObjectProvider
lediglich als Ausgangspunkt für Entwickler gedacht ist , um ihre eigenen benutzerdefinierten Typen zu implementieren, die den dynamischen Versand mit benutzerdefiniertem zugrunde liegenden Speicher- und Abrufverhalten unterstützen, damit der dynamische Versand funktioniert.
Kurz gesagt, verwenden Sie DynamicObject, wenn Sie Ihre EIGENEN Typen erstellen möchten, die mit dem DLR verwendet werden können, und mit den von Ihnen gewünschten CUSTOM-Verhaltensweisen arbeiten möchten.
Beispiel: Stellen Sie sich vor, Sie möchten einen dynamischen Typ haben, der einen benutzerdefinierten Standard zurückgibt, wenn versucht wird, ein Mitglied abzurufen, das NICHT vorhanden ist (dh zur Laufzeit nicht hinzugefügt wurde). Und diese Standardeinstellung lautet: "Es tut mir leid, in diesem Glas befinden sich keine Cookies!". Wenn Sie ein dynamisches Objekt möchten, das sich so verhält, müssen Sie steuern, was passiert, wenn ein Feld nicht gefunden wird. ExpandoObject lässt Sie dies nicht zu. Sie müssen also Ihren eigenen Typ mit einem eindeutigen Verhalten für die dynamische Elementauflösung (Versand) erstellen und diesen anstelle des vorgefertigten verwenden ExpandoObject
.
Sie können einen Typ wie folgt erstellen: (Beachten Sie, dass der folgende Code nur zur Veranschaulichung dient und möglicherweise nicht ausgeführt wird. Um zu erfahren, wie Sie DynamicObject ordnungsgemäß verwenden, finden Sie an anderer Stelle viele Artikel und Tutorials.)
public class MyNoCookiesInTheJarDynamicObject : DynamicObject
{
Dictionary<string, object> properties = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (properties.ContainsKey(binder.Name))
{
result = properties[binder.Name];
return true;
}
else
{
result = "I'm sorry, there are no cookies in this jar!"; //<-- THIS IS OUR
CUSTOM "NO COOKIES IN THE JAR" RESPONSE FROM OUR DYNAMIC TYPE WHEN AN UNKNOWN FIELD IS ACCESSED
return false;
}
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
properties[binder.Name] = value;
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
dynamic method = properties[binder.Name];
result = method(args[0].ToString(), args[1].ToString());
return true;
}
}
Jetzt können wir diese imaginäre Klasse, die wir gerade erstellt haben, als dynamischen Typ verwenden, der ein sehr benutzerdefiniertes Verhalten aufweist, wenn das Feld nicht vorhanden ist.
dynamic d = new MyNoCookiesInTheJarDynamicObject();
var s = d.FieldThatDoesntExist;
//in our contrived example, the below should evaluate to true
Assert.IsTrue(s == "I'm sorry, there are no cookies in this jar!")
ExpandoObject
ist eine vollständige Implementierung von IDynamicMetaObjectProvider
, bei der das .NET Framework-Team all diese Entscheidungen für Sie getroffen hat. Dies ist nützlich, wenn Sie kein benutzerdefiniertes Verhalten benötigen und ExpandoObject Ihrer Meinung nach gut genug für Sie funktioniert (in 90% der Fälle ExpandoObject
ist es gut genug). Sehen Sie sich zum Beispiel Folgendes an, und für ExpandoObject haben die Designer beschlossen, eine Ausnahme auszulösen, wenn das dynamische Element nicht vorhanden ist.
dynamic d = new ExpandoObject();
/*
The ExpandoObject designers chose that this operation should result in an
Exception. They did not have to make that choice, null could
have been returned, for example; or the designers could've returned a "sorry no cookies in the jar" response like in our custom class. However, if you choose to use
ExpandoObject, you have chosen to go with their particular implementation
of DynamicObject behavior.
*/
try {
var s = d.FieldThatDoesntExist;
}
catch(RuntimeBinderException) { ... }
Zusammenfassend ExpandoObject
ist dies einfach eine vorgewählte Möglichkeit, DynamicObject um bestimmte dynamische Versandverhalten zu erweitern, die wahrscheinlich für Sie funktionieren werden , jedoch möglicherweise nicht von Ihren speziellen Anforderungen abhängen.
Während DyanmicObject
ist ein Helfer BaseType, der die Implementierung Ihrer eigenen Typen mit einzigartigen dynamischen Verhaltensweisen einfach und leicht macht.
Ein nützliches Tutorial, auf dem ein Großteil der obigen Beispielquelle basiert.
DynamicObject
: TryGetMember
Wenn Sie beim Überschreiben false zurückgeben, RuntimeBinderException
wird beim Versuch, auf nicht vorhandene Eigenschaften zuzugreifen, a ausgelöst. Damit das Snippet tatsächlich funktioniert, sollten Sie zurückkehren true
.
Gemäß der C # -Sprachenspezifikation dynamic
handelt es sich um eine Typdeklaration. Dh dynamic x
bedeutet, dass die Variable x
den Typ hat dynamic
.
DynamicObject
ist ein Typ, der die Implementierung erleichtert IDynamicMetaObjectProvider
und somit das spezifische Bindungsverhalten für den Typ überschreibt.
ExpandoObject
ist ein Typ, der sich wie eine Eigenschaftstasche verhält. Das heißt, Sie können dynamischen Instanzen dieses Typs zur Laufzeit Eigenschaften, Methoden usw. hinzufügen.
dynamic
ist kein tatsächlicher Typ ... es ist nur ein Hinweis, den Compiler anzuweisen, die späte Bindung für diese Variable zu verwenden. dynamic
Variablen werden tatsächlich wie object
in MSIL
Das obige Beispiel von DynamicObject
zeigt den Unterschied nicht klar, da es im Grunde die Funktionalität implementiert, die bereits von bereitgestellt wirdExpandoObject
.
In den beiden unten genannten Links ist es sehr klar, dass es mit Hilfe von DynamicObject
möglich ist, den tatsächlichen Typ beizubehalten / zu ändern (XElement
in dem in den folgenden Links verwendeten Beispiel) und die Eigenschaften und Methoden besser zu steuern.
public class DynamicXMLNode : DynamicObject
{
XElement node;
public DynamicXMLNode(XElement node)
{
this.node = node;
}
public DynamicXMLNode()
{
}
public DynamicXMLNode(String name)
{
node = new XElement(name);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
XElement setNode = node.Element(binder.Name);
if (setNode != null)
setNode.SetValue(value);
else
{
if (value.GetType() == typeof(DynamicXMLNode))
node.Add(new XElement(binder.Name));
else
node.Add(new XElement(binder.Name, value));
}
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
XElement getNode = node.Element(binder.Name);
if (getNode != null)
{
result = new DynamicXMLNode(getNode);
return true;
}
else
{
result = null;
return false;
}
}
}