it-swarm.com.de

Unterschiede zwischen ExpandoObject, DynamicObject und Dynamic

Was sind die Unterschiede zwischen System.Dynamic.ExpandoObject, System.Dynamic.DynamicObject und dynamic?

In welchen Situationen verwenden Sie diese Typen?

151
M4N

Das Schlüsselwort dynamic wird verwendet, um Variablen zu deklarieren, die später gebunden werden sollen.
Wenn Sie das Late-Binding für einen realen oder imaginären Typ verwenden möchten, verwenden Sie das Schlüsselwort dynamic. Der Rest erledigt der Compiler.

Wenn Sie das Schlüsselwort dynamic für die Interaktion mit einer normalen Instanz verwenden, führt DLR spät gebundene Aufrufe der normalen Methoden der Instanz aus.

Die IDynamicMetaObjectProvider-Schnittstelle ermöglicht einer Klasse, die Kontrolle über ihr spät gebundenes Verhalten zu übernehmen.
Wenn Sie das Schlüsselwort dynamic verwenden, um mit einer IDynamicMetaObjectProvider-Implementierung zu interagieren, ruft der 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 einer Instanz Mitglieder hinzufügen und diese dynamically verwenden können.
DynamicObject ist eine erweiterte Implementierung, die vererbt werden kann, um auf einfache Weise benutzerdefiniertes Verhalten bereitzustellen.

136
SLaks

Ich werde versuchen, eine klarere Antwort auf diese Frage zu geben, um klar zu erklären, was die Unterschiede zwischen Dynamik, ExpandoObject und DynamicObject sind.

Sehr schnell ist dynamic ein Schlüsselwort. Es ist kein Typ an sich. Mit diesem Schlüsselwort wird der Compiler angewiesen, die statische Typüberprüfung zur Entwurfszeit zu ignorieren und stattdessen die spätere Bindung zur Laufzeit zu verwenden. Wir werden also im Rest dieser Antwort nicht viel Zeit mit dynamic verbringen.

ExpandoObject und DynamicObject sind in der Tat Typen. Auf der Oberfläche sehen sie sich sehr ähnlich aus. Beide Klassen implementieren IDynamicMetaObjectProvider. Dig jedoch tiefer und Sie werden feststellen, dass sie sich überhaupt nicht ähneln.

DynamicObject ist eine Teilimplementierung von IDynamicMetaObjectProvider und dient lediglich als Ausgangspunkt für Entwickler, um ihre eigenen benutzerdefinierten Typen zu implementieren, die dynamischen Versand mit benutzerdefiniertem zugrunde liegenden Speicher- und Abrufverhalten unterstützen, um den dynamischen Versand zu ermöglichen.

  1. DynamicObject kann nicht direkt erstellt werden.
  2. Sie MÜSSEN DynamicObject so erweitern, dass Sie als Entwickler davon profitieren können.
  3. Wenn Sie DynamicObject erweitern, können Sie jetzt CUSTOM-Verhalten in Bezug auf die Auflösung von Dynamic Dispatch in Daten angeben, die intern zur Laufzeit in der zugrunde liegenden Datendarstellung gespeichert sind.
  4. ExpandoObject speichert zugrunde liegende Daten in einem Wörterbuch usw. Wenn Sie DynamicObject implementieren, können Sie Daten an beliebiger Stelle speichern. (Wie Sie die Daten beim Versand abrufen und festlegen, bleibt Ihnen überlassen).

Kurz gesagt, verwenden Sie DynamicObject, wenn Sie eigene OWN-Typen erstellen möchten, die mit dem DLR verwendet werden können, und mit beliebigen benutzerdefinierten Verhaltensweisen arbeiten können, die Sie möchten.

Beispiel: Stellen Sie sich vor, Sie möchten einen dynamischen Typ haben, der einen benutzerdefinierten Standardwert zurückgibt, wenn ein Abruf für ein nicht vorhandenes Element versucht wird (d. H. Zur Laufzeit nicht hinzugefügt wurde). Und dieser Standard sagt: "Es tut mir leid, es gibt keine Cookies in diesem Glas!". Wenn Sie ein dynamisches Objekt wünschen, 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 eindeutigem Verhalten für die dynamische Mitgliederauflösung (Dispatch) erstellen und diesen anstelle des vorgefertigten ExpandoObject verwenden. 

Sie können einen Typ wie folgt erstellen: (Beachten Sie, der folgende Code dient nur zur Veranschaulichung und wird möglicherweise nicht ausgeführt. Um zu lernen, wie Sie DynamicObject richtig verwenden, finden Sie an anderer Stelle viele Artikel und Lernprogramme.)

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;
    }
}

Wir könnten 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 Sie der Meinung sind, dass ExpandoObject für Sie gut genug ist (in 90% der Fälle ist ExpandoObject gut genug). Siehe zum Beispiel Folgendes und das für ExpandoObject. Die Designer entschieden sich für eine Ausnahme, 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 ist ExpandoObject eine vorgewählte Methode, um DynamicObject mit bestimmten dynamischen Dispatch-Verhaltensweisen zu erweitern, die wahrscheinlich für Sie funktionieren, aber möglicherweise nicht von Ihren speziellen Anforderungen abhängen.

DyanmicObject ist dagegen ein Helfer-BaseType, der die Implementierung eigener Typen mit einzigartigem dynamischen Verhalten einfach und unkompliziert macht.

Ein nützliches Tutorial, auf dem ein Großteil der obigen Beispielquelle basiert.

39
Ayo I

Gemäß der C # -Sprachenspezifikation ist dynamic eine Typdeklaration. Das heißt dynamic x bedeutet, dass die Variable x den Typ dynamic hat. 

DynamicObject ist ein Typ, der die Implementierung von IDynamicMetaObjectProvider erleichtert und somit das spezifische Bindungsverhalten für den Typ überschreibt.

ExpandoObject ist ein Typ, der sich wie ein Eigenschaftsbeutel verhält. Das heißt Sie können zur Laufzeit Eigenschaften, Methoden usw. zu dynamischen Instanzen dieses Typs hinzufügen. 

34
Brian Rasmussen

Das obige Beispiel von DynamicObject macht den Unterschied nicht klar, da es im Wesentlichen die Funktionalität implementiert, die bereits von ExpandoObject bereitgestellt wird.

In den beiden unten genannten Links ist es sehr klar, dass es mit Hilfe von DynamicObject möglich ist, den tatsächlichen Typ (XElement im in den folgenden Links verwendeten Beispiel) beizubehalten/zu ändern und Eigenschaften und Methoden besser zu steuern.

https://blogs.msdn.Microsoft.com/csharpfaq/2009/09/30/dynamic-in-c-4-0-introducing-the-expandoobject/

https://blogs.msdn.Microsoft.com/csharpfaq/2009/10/19/dynamic-in-c-4-0-creating-wrappers-with-dynamicobject/

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;    
        }    
    }    
}
0
Deepak Mishra