Antworten:
Das dynamicSchlü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 dynamicSchlüsselwort verwenden, um mit einer normalen Instanz, dem DLR, zu interagieren spät gebundene Aufrufe der normalen Methoden der Instanz durch.
Die IDynamicMetaObjectProviderSchnittstelle ermöglicht es einer Klasse, die Kontrolle über ihr spät gebundenes Verhalten zu übernehmen.
Wenn Sie das dynamicSchlüsselwort für die Interaktion mit einer IDynamicMetaObjectProviderImplementierung verwenden, ruft das DLR die IDynamicMetaObjectProviderMethoden auf und das Objekt selbst entscheidet, was zu tun ist.
Die ExpandoObjectund DynamicObjectKlassen sind Implementierungen von IDynamicMetaObjectProvider.
ExpandoObjectist eine einfache Klasse, mit der Sie Mitglieder zu einer Instanz hinzufügen und sie als dynamicVerbündeten verwenden können .
DynamicObjectist 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 ExpandoObjectund sindDynamicObject .
Sehr schnell dynamicist 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 dynamicim Rest dieser Antwort nicht viel Zeit damit verbringen .
ExpandoObjectund DynamicObjectsind 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 IDynamicMetaObjectProviderlediglich 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!")
ExpandoObjectist 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 ExpandoObjectist 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 ExpandoObjectist 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 DyanmicObjectist 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: TryGetMemberWenn Sie beim Überschreiben false zurückgeben, RuntimeBinderExceptionwird 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 dynamichandelt es sich um eine Typdeklaration. Dh dynamic xbedeutet, dass die Variable xden Typ hat dynamic.
DynamicObjectist ein Typ, der die Implementierung erleichtert IDynamicMetaObjectProviderund somit das spezifische Bindungsverhalten für den Typ überschreibt.
ExpandoObjectist 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.
dynamicist kein tatsächlicher Typ ... es ist nur ein Hinweis, den Compiler anzuweisen, die späte Bindung für diese Variable zu verwenden. dynamicVariablen werden tatsächlich wie objectin MSIL
Das obige Beispiel von DynamicObjectzeigt 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 DynamicObjectmö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;
}
}
}