回答:
dynamic
キーワードは、遅延バインドされなければならない変数を宣言するために使用されます。
遅延バインディングを使用する場合は、実際のタイプまたは想定されたタイプに対して、dynamic
キーワードと、コンパイラーが残りの処理を実行します。
dynamic
キーワードを使用して通常のインスタンスと対話する場合、DLRはインスタンスの通常のメソッドに対して遅延バインディング呼び出しを実行します。
このIDynamicMetaObjectProvider
インターフェースにより、クラスは遅延バインディング動作を制御できます。キーワードを
使用dynamic
してIDynamicMetaObjectProvider
実装とやり取りすると、DLRがIDynamicMetaObjectProvider
メソッドを呼び出し、オブジェクト自体が何をすべきかを決定します。
ExpandoObject
そしてDynamicObject
クラスはの実装ですIDynamicMetaObjectProvider
。
ExpandoObject
は、インスタンスにメンバーを追加し、それらをdynamic
同盟国として使用できるようにする単純なクラスです。
DynamicObject
より高度な実装であり、継承して簡単にカスタマイズされた動作を提供できます。
この質問に対する明確な回答を提供し、ダイナミックExpandoObject
とダイナミックの違いを明確に説明するように努めますDynamicObject
ます。
非常に早く、dynamic
キーワードです。それ自体はタイプではありません。これは、設計時に静的型チェックを無視し、代わりに実行時に遅延バインディングを使用するようコンパイラーに指示するキーワードです。したがってdynamic
、この回答の残りの部分ではあまり時間をかけません。
ExpandoObject
そしてDynamicObject
確かなタイプです。SURFACEでは、それらは互いに非常によく似ています。両方のクラスが実装しIDynamicMetaObjectProvider
ます。ただし、深く掘り下げてみると、まったく同じではないことがわかります。
DynamicObjectは、IDynamicMetaObjectProvider
開発者が動的ディスパッチをサポートする独自のカスタム型を実装して、動的なディスパッチを機能させるためのカスタムの基になるストレージと取得動作を実装するための開始点であることを純粋に意図した部分実装です。
つまり、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は、独自の型を独自の動的動作で簡単に実装できるようにします。
DynamicObject
:オーバーライドTryGetMember
するときにfalseを返すと、RuntimeBinderException
存在しないプロパティにアクセスしようとするとa がスローされます。スニペットが実際に機能するには、戻りtrue
ます。
C#言語仕様によるdynamic
と、型宣言です。すなわちdynamic x
、変数が意味x
のタイプがありますdynamic
。
DynamicObject
は、実装IDynamicMetaObjectProvider
を簡単にし、その型の特定のバインディング動作をオーバーライドする型です。
ExpandoObject
プロパティバッグのように機能するタイプです。つまり、実行時にこのタイプの動的インスタンスにプロパティやメソッドなどを追加できます。
dynamic
は実際の型ではありません...これは、この変数に遅延バインディングを使用するようコンパイラーに指示するためのヒントにすぎません。dynamic
変数は実際にはobject
MSILのように宣言されます
上記の例で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;
}
}
}