web-dev-qa-db-ja.com

ExpandoObject、DynamicObject、およびdynamicの違い

System.Dynamic.ExpandoObjectSystem.Dynamic.DynamicObject、およびdynamicの違いは何ですか?

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

160
M4N

dynamicキーワードは、遅延バインドする必要がある変数を宣言するために使用されます。
遅延バインディングを使用する場合は、実数型または想像型に対して、dynamicキーワードを使用し、残りはコンパイラーが行います。

dynamicキーワードを使用して通常のインスタンスと対話する場合、 [〜#〜] dlr [〜#〜] はインスタンスの通常のメソッドへの遅延バインド呼び出しを実行します。

IDynamicMetaObjectProvider interface を使用すると、クラスが遅延バインディングの動作を制御できます。
dynamicキーワードを使用してIDynamicMetaObjectProvider実装と対話する場合、DLRはIDynamicMetaObjectProviderメソッドを呼び出し、オブジェクト自体が処理を決定します。

ExpandoObjectおよびDynamicObjectクラスは、IDynamicMetaObjectProviderの実装です。

ExpandoObjectは、インスタンスにメンバーを追加し、dynamicallyを使用できるシンプルなクラスです。
DynamicObjectは、カスタマイズされた動作を簡単に提供するために継承できる、より高度な実装です。

140
SLaks

動的なExpandoObjectDynamicObjectの違いを明確に説明するために、この質問に対してより明確な回答を提供しようとします。

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

ExpandoObjectDynamicObjectは確かに型です。表面では、それらは互いに非常によく似ています。両方のクラスはIDynamicMetaObjectProviderを実装します。しかし、より深く掘り下げると、それらはまったく似ていないことがわかります。

DynamicObjectは、IDynamicMetaObjectProviderの部分的な実装であり、開発者が独自のカスタムタイプを実装して、動的なディスパッチを行うために、基礎となるカスタムストレージおよび取得動作による動的ディスパッチをサポートすることを目的としています。 work。

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

要するに、DLRで使用できるOWNタイプを作成し、任意のCUSTOMビヘイビアーを操作する場合に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!")

ExpandoObjectIDynamicMetaObjectProviderの完全な実装であり、.NET Frameworkチームがこれらすべての決定を行っています。これは、カスタム動作を必要とせず、ExpandoObjectが十分に機能すると感じている場合に役立ちます(90%の時間、ExpandoObjectで十分です)。したがって、たとえば、以下を参照してください。ExpandoObjectの場合、設計者は動的メンバーが存在しない場合に例外をスローすることを選択しました。

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です。

上記の例のソースの多くが基づいている有用なチュートリアル

51
Ayo I

C#言語仕様によれば、dynamicは型宣言です。つまりdynamic xは、変数xのタイプがdynamicであることを意味します。

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

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

34
Brian Rasmussen

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