ExpandoObjectの真のメリットは何ですか?


587

ExpandoObjectの .NET 4に追加されたクラスでは、任意の実行時にオブジェクトにプロパティを設定することができます。

Dictionary<string, object>、または本当にハッシュテーブルを使用するよりも優れている点はありますか?私の知る限り、これはハッシュテーブルにすぎず、もう少し簡潔な構文でアクセスできます。

たとえば、これはなぜですか:

dynamic obj = new ExpandoObject();
obj.MyInt = 3;
obj.MyString = "Foo";
Console.WriteLine(obj.MyString);

次のものよりも本当に良い、または大幅に異なる:

var obj = new Dictionary<string, object>();
obj["MyInt"] = 3;
obj["MyString"] = "Foo";

Console.WriteLine(obj["MyString"]);

実行時に決定されるタイプを使用していることが明らかでない場合を除いて、任意のディクショナリタイプを使用する代わりにExpandoObjectを使用することによって得られる実際の利点は何ですか。

回答:


689

あなたが言及しているMSDNの記事を書いたので、これに答える必要があると思います。

最初に、私はこの質問を予想していたので、ExpandoObject:Dynamic in C#4.0:Introducing the ExpandoObjectの多かれ少なかれ実際の使用例を示すブログ投稿を書きました。

まもなく、ExpandoObjectは、複雑な階層オブジェクトを作成するのに役立ちます。たとえば、辞書内に辞書があるとします。

Dictionary<String, object> dict = new Dictionary<string, object>();
Dictionary<String, object> address = new Dictionary<string,object>();
dict["Address"] = address;
address["State"] = "WA";
Console.WriteLine(((Dictionary<string,object>)dict["Address"])["State"]);

より深いのは階層であり、醜いのはコードです。ExpandoObjectを使用すると、エレガントで読みやすくなります。

dynamic expando = new ExpandoObject();
expando.Address = new ExpandoObject();
expando.Address.State = "WA";
Console.WriteLine(expando.Address.State);

次に、すでに指摘したように、ExpandoObjectはINotifyPropertyChangedインターフェイスを実装しており、ディクショナリよりもプロパティを詳細に制御できます。

最後に、次のようにExpandoObjectにイベントを追加できます。

class Program
{
   static void Main(string[] args)
   {
       dynamic d = new ExpandoObject();

       // Initialize the event to null (meaning no handlers)
       d.MyEvent = null;

       // Add some handlers
       d.MyEvent += new EventHandler(OnMyEvent);
       d.MyEvent += new EventHandler(OnMyEvent2);

       // Fire the event
       EventHandler e = d.MyEvent;

       e?.Invoke(d, new EventArgs());
   }

   static void OnMyEvent(object sender, EventArgs e)
   {
       Console.WriteLine("OnMyEvent fired by: {0}", sender);
   }

   static void OnMyEvent2(object sender, EventArgs e)
   {
       Console.WriteLine("OnMyEvent2 fired by: {0}", sender);
   }
}

また、動的にイベント引数を受け入れることを妨げるものは何もないことに注意してください。つまり、を使用する代わりにEventHandler、を使用EventHandler<dynamic>すると、ハンドラの2番目の引数がになりますdynamic


53
面白い。情報re:イベントをありがとう。それは私にとって新しいものでした。
リードコプシー、

16
@AlexandraRusina、あなたが言うときにそれがイベントであることをどうやって知るのですかd.MyEvent = null;、そうでないのですか?
Shimmy Weitzhandler

20
多分私は何かが足りないかもしれませんが、これはイベントではありません-これはデリゲート型の単純なプロパティです。
Sergey Berezovskiy

7
最初のブロックは匿名型を使って書くことができます:var expando = new { Address = new { State = "WA" } }; Console.WriteLine(expando.Address.State);私はこれはもっと読みやすいですがymmvです。また、静的に型付けされているため、このコンテキストではより便利です。
nawfal 2013年

13
@nawfalは正しくありません-匿名はExpandoとは異なります。匿名型を作成しているため、任意のプロパティを追加できません。
Blowhard博士2014

75

1つの利点は、バインドシナリオです。データグリッドとプロパティグリッドは、TypeDescriptorシステムを介して動的プロパティを取得します。さらに、WPFデータバインディングは動的プロパティを理解するため、WPFコントロールはディクショナリよりも簡単にExpandoObjectにバインドできます。

一部のシナリオでは、ディクショナリエントリではなくDLRプロパティを期待する動的言語との相互運用性も考慮事項となる場合があります。


6
動的オブジェクトへのデータバインディングが壊れているようです。レポートユーザーのeisenbergeffectが、SOとcaliburn.microのコーディネーターにいます。@AlexandraRusinaは、バグの状態と「修正できない」というステータスについてコメントできます
surfmuggle

2
好奇心旺盛な方のために、私は現在WPF4 にバインドしList<dynamic>IEnumerable<dynamic>使用することができます
Graham Bass

47

私にとっての本当の利点は、XAMLからの完全に簡単なデータバインディングです。

public dynamic SomeData { get; set; }

...

SomeData.WhatEver = "Yo Man!";

...

 <TextBlock Text="{Binding SomeData.WhatEver}" />

28

に基づいて構築された他の言語との相互運用は、DLR私が考えることができる第1の理由です。あなたはそれらを渡すことはできませんDictionary<string, object>、それはありませんようIDynamicMetaObjectProvider。もう1つの追加の利点はINotifyPropertyChanged、WPFのデータバインディングの世界で実装するというDictionary<K,V>ことです。これは、WPF が提供できるものを超える利点も追加することを意味します。


19

プログラマの利便性がすべてです。私は、このオブジェクトを使って素早く汚れたプログラムを書くことを想像できます。


9
@J。ヘンドリックス、彼も「汚い」と言ったことを忘れないでください。Intellisenseには欠点がありますが、デバッグとバグの検出が容易になります。私は奇妙な(そして常にまれな)ケースを扱わない限り、私はまだ動的型よりも静的型を好みます。
Phil

便宜上+1。ただし、匿名型は単純なプロパティバッグと同じくらい便利で、静的性が優れていることがわかります。
nawfal 2013年

1
プロダクションコードでは使用したくありませんが、テストコードでは非常に便利で、非常に美しく見せることができます。
トビアス

14

辞書を使用して動的に追加されたプロパティを "偽造"する必要がなくなるため、構文上の利点があると思います。

それと、私は動的言語との相互運用を考えます。


11

これは、ExpandoObjectを使用して、着信する構造化データ(つまり、XML、Json)の動的なアドホックタイプを作成することに関するすばらしいMSDN記事の例です。

デリゲートをExpandoObjectの動的プロパティに割り当てることもできます。

dynamic person = new ExpandoObject();
person.FirstName = "Dino";
person.LastName = "Esposito";

person.GetFullName = (Func<String>)(() => { 
  return String.Format("{0}, {1}", 
    person.LastName, person.FirstName); 
});

var name = person.GetFullName();
Console.WriteLine(name);

したがって、実行時に動的オブジェクトにロジックを挿入することができます。したがって、ラムダ式、クロージャー、動的キーワード、DynamicObjectクラス一緒に、関数型プログラミングのいくつかの要素をC#コードに導入できます。これは、JavaScriptやPHPなどの動的言語からわかっています。


4

これが便利な場合があります。たとえば、モジュール化されたシェルに使用します。各モジュールは、その設定にバインドされた独自の構成ダイアログデータを定義します。DatacontextとしてExpandoObjectを提供し、値を構成ストレージに保存します。このように、構成ダイアログライターは値にバインドするだけで、自動的に作成および保存されます。(もちろん、これらの設定を使用するためのモジュールに提供されます)

辞書よりも簡単に使用できます。しかし、内部的には単なる辞書であることに誰もが気づくべきです。

これはLINQのような単なる構文上の砂糖ですが、場合によっては物事が簡単になることもあります。

だからあなたの質問に直接答えるために:書くことも読むことも簡単です。しかし、技術的には本質的にaですDictionary<string,object>(値をリストするために1つにキャストすることもできます)。


-1
var obj = new Dictionary<string, object>;
...
Console.WriteLine(obj["MyString"]);

すべてがToString()を持っているので、それが機能するだけだと思います。それ以外の場合は、それがあった型を知っていて、「オブジェクト」をその型にキャストする必要があります。


これらのいくつかは他よりも頻繁に有用です、私は徹底しようとしています。

  1. より直接的なドット表記を使用して、コレクション(実際には「辞書」)にアクセスする方がはるかに自然な場合があります。

  2. これは本当に素晴らしいタプルとして使用できるようです。メンバーを「Item1」、「Item2」などと呼ぶことはできますが、タプルとは異なり、変更する必要はありません。これには、インテリセンスのサポートがないという大きな欠点があります。

  3. 辞書の感触と同様に、「メンバー名を文字列として」に不快に感じるかもしれません。「文字列を実行する」のように感じすぎて、命名規則がコード化され、形態素やコードがメンバーを使用する方法を理解しようとしているときの音節:-P

  4. ExpandoObject自体に値を割り当てることはできますか?dynamic / dynamic []と比較して、ニーズに最適な方を使用してください。

  5. dynamic / dynamic []はforeachループでは機能しないと思います。varを使用する必要がありますが、おそらくExpandoObjectを使用できます。

  6. クラス内のデータメンバーとしてダイナミックを使用することはできません。おそらくそれが少なくともキーワードのようなものであるため、ExpandoObjectを使用してうまくいけば可能です。

  7. 私はそれがExpandoObjectであることを期待しています。非常に一般的なものにラベルを付けるのに役立つかもしれません。使用される動的なものがたくさんあるタイプに基づいて区別するコードがあります。


一度に複数のレベルをドリルダウンできれば、すばらしいことです。

var e = new ExpandoObject();
e.position.x = 5;
etc...

これは最良の例ではありません。自分のプロジェクトで適切なエレガントな使い方を想像してみてください。

コードでこれらの一部をビルドして、結果をインテリセンスにプッシュすることはできません。これがどのように機能するかはわかりません。

メンバーだけでなく価値を持つことができるのであれば、良いことです。

var fifteen = new ExpandoObject();
fifteen = 15;
fifteen.tens = 1;
fifteen.units = 5;
fifteen.ToString() = "fifteen";
etc...

-3

valueTuplesの後、ExpandoObjectクラスの使用は何ですか?ExpandoObjectを使用したこの6行のコード:

dynamic T = new ExpandoObject();
T.x = 1;
T.y = 2;
T.z = new ExpandoObject();
T.z.a = 3;
T.b= 4;

タプルで一行に書くことができます:

var T = (x: 1, y: 2, z: (a: 3, b: 4));

タプル構文の他に、強い型推論とインテリセンスのサポートがあります


1
例は、値のタプルではTc = 5を記述できないという意味で同一ではありません。Tの定義が完了したら、Tを展開します。ExpandoObjectを使用すると、動的であるため、それを行うことができます。値のタプルを使用した例は、匿名型の宣言と非常によく似ています。例:var T2 = new {x = 1、y = 2、z = new {a = 3、b = 4}};
LxL 2018

定義せずにTc = 5を記述する必要があるのはなぜですか?ExpandoObjectは、.netで定義されていないCOMオブジェクトを処理する場合にのみ役立ちます。それ以外の場合は、このExpandoObjectを使用することはありません。これは、設計時と実行時の両方でダーティでバグがあるためです。
エンジニアリング M・ハムディ

1
最初に(a:3、b:4)にzを割り当て、その後、zに追加のcプロパティを割り当てたいと思いませんか?バリュータプルでそれを行うことができますか?
LxL 2018

したがって、私の目的は、ExpandoObjectと値タプルを異なる目的で設計されているため、それらを比較できないことです。あなたのやり方を比較することにより、ExpandoObjectが設計された機能、つまり動的構造を却下しました。
LxL 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.