System.Dynamic.ExpandoObject
、System.Dynamic.DynamicObject
、およびdynamic
の違いは何ですか?
どのような状況でこれらのタイプを使用しますか?
dynamic
キーワードは、遅延バインドする必要がある変数を宣言するために使用されます。
遅延バインディングを使用する場合は、実数型または想像型に対して、dynamic
キーワードを使用し、残りはコンパイラーが行います。
dynamic
キーワードを使用して通常のインスタンスと対話する場合、 [〜#〜] dlr [〜#〜] はインスタンスの通常のメソッドへの遅延バインド呼び出しを実行します。
IDynamicMetaObjectProvider
interface を使用すると、クラスが遅延バインディングの動作を制御できます。dynamic
キーワードを使用してIDynamicMetaObjectProvider
実装と対話する場合、DLRはIDynamicMetaObjectProvider
メソッドを呼び出し、オブジェクト自体が処理を決定します。
ExpandoObject
およびDynamicObject
クラスは、IDynamicMetaObjectProvider
の実装です。
ExpandoObject
は、インスタンスにメンバーを追加し、dynamic
allyを使用できるシンプルなクラスです。DynamicObject
は、カスタマイズされた動作を簡単に提供するために継承できる、より高度な実装です。
動的なExpandoObject
とDynamicObject
の違いを明確に説明するために、この質問に対してより明確な回答を提供しようとします。
非常に迅速に、dynamic
はキーワードです。それ自体は型ではありません。これは、設計時に静的型チェックを無視し、代わりに実行時に遅延バインディングを使用するようにコンパイラーに指示するキーワードです。したがって、この回答の残りの部分では、dynamic
にあまり時間を費やしません。
ExpandoObject
とDynamicObject
は確かに型です。表面では、それらは互いに非常によく似ています。両方のクラスはIDynamicMetaObjectProvider
を実装します。しかし、より深く掘り下げると、それらはまったく似ていないことがわかります。
DynamicObjectは、IDynamicMetaObjectProvider
の部分的な実装であり、開発者が独自のカスタムタイプを実装して、動的なディスパッチを行うために、基礎となるカスタムストレージおよび取得動作による動的ディスパッチをサポートすることを目的としています。 work。
要するに、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!")
ExpandoObject
はIDynamicMetaObjectProvider
の完全な実装であり、.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です。
C#言語仕様によれば、dynamic
は型宣言です。つまりdynamic x
は、変数x
のタイプがdynamic
であることを意味します。
DynamicObject
は、IDynamicMetaObjectProvider
を簡単に実装できるタイプであり、そのタイプの特定のバインディング動作をオーバーライドします。
ExpandoObject
は、プロパティバッグのように機能するタイプです。つまり実行時に、このタイプの動的インスタンスにプロパティ、メソッドなどを追加できます。
上記のDynamicObject
の例は、ExpandoObject
によってすでに提供されている機能を基本的に実装しているため、違いを明確に示していません。
下記の2つのリンクでは、DynamicObject
の助けを借りて、実際の型(以下のリンクで使用されている例ではXElement
)を保持/変更できることが非常に明確です。プロパティとメソッドの制御。
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;
}
}
}