ExpandoObject、DynamicObject、およびダイナミックの違い


170

どのような違いがありSystem.Dynamic.ExpandoObjectSystem.Dynamic.DynamicObjectdynamic

どのような状況でこれらのタイプを使用しますか?

回答:


154

dynamicキーワードは、遅延バインドされなければならない変数を宣言するために使用されます。
遅延バインディングを使用する場合は、実際のタイプまたは想定されたタイプに対して、dynamicキーワードと、コンパイラーが残りの処理を実行します。

dynamicキーワードを使用して通常のインスタンスと対話する場合、DLRはインスタンスの通常のメソッドに対して遅延バインディング呼び出しを実行します。

このIDynamicMetaObjectProviderインターフェースにより、クラスは遅延バインディング動作を制御できます。キーワードを
使用dynamicしてIDynamicMetaObjectProvider実装とやり取りすると、DLRがIDynamicMetaObjectProviderメソッドを呼び出し、オブジェクト自体が何をすべきかを決定します。

ExpandoObjectそしてDynamicObjectクラスはの実装ですIDynamicMetaObjectProvider

ExpandoObjectは、インスタンスにメンバーを追加し、それらをdynamic同盟国として使用できるようにする単純なクラスです。
DynamicObjectより高度な実装であり、継承して簡単にカスタマイズされた動作を提供できます。


2
これについてもっと学ぶための良い場所は何でしょうか?APIではなく、なぜAPIの背後にあるのですか?たとえば、ExpandoObjectがルビーの「method_missing」ベースのプログラミングの事実上の基本型であるDynamicObjectから派生しないのはなぜですか。
紀州

4
可能な場合、いくつかの使用例を追加できますか?たとえば、DynamicObjectをどのように使用し、どのような利点がありますか?
oɔɯǝɹ

10
このような例のない素晴らしい答えは、クリームが上にないケーキのようです。
Teoman Shipahi 2015


68

この質問に対する明確な回答を提供し、ダイナミックExpandoObjectとダイナミックの違いを明確に説明するように努めますDynamicObjectます。

非常に早く、dynamicキーワードです。それ自体はタイプではありません。これは、設計時に静的型チェックを無視し、代わりに実行時に遅延バインディングを使用するようコンパイラーに指示するキーワードです。したがってdynamic、この回答の残りの部分ではあまり時間をかけません。

ExpandoObjectそしてDynamicObject確かなタイプです。SURFACEでは、それらは互いに非常によく似ています。両方のクラスが実装しIDynamicMetaObjectProviderます。ただし、深く掘り下げてみると、まったく同じではないことがわかります。

DynamicObjectは、IDynamicMetaObjectProvider開発者が動的ディスパッチをサポートする独自のカスタム型を実装して、動的なディスパッチを機能させるためのカスタムの基になるストレージと取得動作を実装するための開始点であることを純粋に意図した部分実装です。

  1. DynamicObjectを直接構築することはできません。
  2. DynamicObjectを拡張して、開発者として使用できるようにする必要があります。
  3. DynamicObjectを拡張すると、動的ディスパッチで実行時に基礎となるデータ表現に内部的に格納されているデータをどのように解決するかに関するCUSTOM動作を提供できるようになります。
  4. ExpandoObjectは、基礎となるデータをディクショナリなどに格納します。DynamicObjectを実装する場合、どこにでも好きなようにデータを格納できます。(たとえば、ディスパッチ時にデータを取得および設定する方法は完全にあなた次第です)。

つまり、DLRで使用できるOWNタイプを作成し、必要なカスタム動作を処理する場合は、DynamicObjectを使用します。

例:存在しない(つまり、実行時に追加されていない)メンバーに対してgetが試行されるたびにカスタムのデフォルトを返す動的なタイプが欲しいと想像してください。そして、デフォルトでは、「申し訳ありませんが、このjarにはcookieがありません!」と表示されます。このように動作する動的オブジェクトが必要な場合は、フィールドが見つからない場合の動作を制御する必要があります。ExpandoObjectはこれを許可しません。したがって、独自の動的メンバー解決(ディスパッチ)動作を備えた独自のタイプを作成し、既成のの代わりにそれを使用する必要がありますExpandoObject

次のようにタイプを作成できます(注:以下のコードは説明のためのものであり、実行されない場合があります。DynamicObjectを適切に使用する方法については、他にも多くの記事やチュートリアルがあります。)

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

これで、作成したこの架空のクラスを、フィールドが存在しない場合に非常にカスタムの動作を持つ動的な型として使用できます。

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はの完全実装でIDynamicMetaObjectProviderあり、.NET Frameworkチームがこれらすべての決定を行います。これは、カスタム動作が不要で、ExpandoObjectが十分に機能していると感じている場合に役立ちます(90%の時間でExpandoObject十分です)。たとえば、以下を参照してください。ExpandObjectの場合、動的メンバーが存在しない場合、デザイナーは例外をスローすることを選択しました。

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) { ... }

つまり、要約すると、ExpandoObjectおそらくあなたのために機能する特定の動的ディスパッチ動作でDynamicObjectを拡張するための事前に選択された方法の1つにすぎません。ません。

一方、DyanmicObjectヘルパーBaseTypeは、独自の型を独自の動的動作で簡単に実装できるようにします。

上記のサンプルソースの多くが基づいている便利なチュートリアル。


とても良い説明。たった1つの技術的な修正:ExpandoObjectはDynamicObjectから継承しません。
Mike Rosoft

の例の小さな修正DynamicObject:オーバーライドTryGetMemberするときにfalseを返すと、RuntimeBinderException存在しないプロパティにアクセスしようとするとa がスローされます。スニペットが実際に機能するには、戻りtrueます。
lluchmk

36

C#言語仕様によるdynamicと、型宣言です。すなわちdynamic x、変数が意味xのタイプがありますdynamic

DynamicObjectは、実装IDynamicMetaObjectProviderを簡単にし、その型の特定のバインディング動作をオーバーライドする型です。

ExpandoObjectプロパティバッグのように機能するタイプです。つまり、実行時にこのタイプの動的インスタンスにプロパティやメソッドなどを追加できます。


25
dynamicは実際の型ではありません...これは、この変数に遅延バインディングを使用するようコンパイラーに指示するためのヒントにすぎません。dynamic変数は実際にはobjectMSILのように宣言されます
Thomas Levesque

1
@Thomas:コンパイラーの観点から見ると、それは型ですが、実行時の表現はObjectの表現です。「静的に型付けされて動的になる」という文は、いくつかのMSプレゼンテーションで見つかります。
Brian Rasmussen、2010

3
@Thomas:そして言語仕様は「C#4.0は動的と呼ばれる新しい静的型を導入する」と述べています。
ブライアンラスムッセン

確かに...しかし、DynamicObjectやExpandoObjectのような型との継承関係がないため、それを型と見なすのは紛らわしいと思います
Thomas Levesque

3
@NathanA私はあなたとここにいます。しかし、言語仕様ではそれをタイプと呼んでいるので、それを私は使っています。
Brian Rasmussen 2014

0

上記の例でDynamicObjectは、基本的にすでに提供されている機能を実装しているため、明確な違いはわかりません。ExpandoObject

下記の2つのリンクでは、の助けを借りてDynamicObject、実際のタイプ(XElement以下のリンクで使用されている例の場合)を保持/変更し、プロパティとメソッドをより適切に制御できることが非常に明確です。

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;    
        }    
    }    
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.