16

必要なメソッドとメソッドを備えた新しいExpandoObject実装があることに気付きました。そのため、アイテムを辞書に追加するのと同じ方法で、コレクション初期化子構文を使用して expando オブジェクトにプロパティを追加できるはずです。IDictionary<string,object>IEnumerable<KeyValuePair<string, object>>Add(string, object)

Dictionary<string,object> dict = new Dictionary<string,object>() 
{
    { "Hello", "World" }
};

dynamic obj = new ExpandoObject()
{
    { "foo", "hello" },
    { "bar", 42 },
    { "baz", new object() }
};

int value = obj.bar;

しかし、それを行う方法はないようです。エラー:

「System.Dynamic.ExpandoObject」には「追加」の定義が含まれていません

インターフェイスが明示的に実装されているため、これは機能しないと思います。しかし、それを回避する方法はありますか?これはうまくいきます、

IDictionary<string, object> exdict = new ExpandoObject() as IDictionary<string, object>();
exdict.Add("foo", "hello");
exdict.Add("bar", 42);
exdict.Add("baz", new object());

しかし、コレクション初期化子の構文ははるかにきれいです。

4

6 に答える 6

6

以前に単純な ExpandoObject 初期化子が必要になったことが何度かありましたが、通常は次の 2 つの拡張メソッドを使用して初期化構文のようなものを実現しています。

public static KeyValuePair<string, object> WithValue(this string key, object value)
{
    return new KeyValuePair<string, object>(key, value);
}

public static ExpandoObject Init(
    this ExpandoObject expando, params KeyValuePair<string, object>[] values)
{
    foreach(KeyValuePair<string, object> kvp in values)
    {
        ((IDictionary<string, Object>)expando)[kvp.Key] = kvp.Value;
    }
    return expando;
}

次に、次のように記述できます。

dynamic foo = new ExpandoObject().Init(
    "A".WithValue(true),
    "B".WithValue("Bar"));

KeyValuePair<string, object>一般に、文字列キーからインスタンスを構築するための拡張メソッドがあると便利であることがわかりました。構文をさらに簡潔にする必要がある場合にIs記述できるように、明らかに名前を次のようなものに変更できます。"Key".Is("Value")

于 2012-05-01T18:31:35.767 に答える
3

言語仕様 (Collection Initializers の 7.5.10.3) は、私が知る限り、この点について少しあいまいです。それは言う

指定された要素ごとに、コレクション初期化子は、要素初期化子の式リストを引数リストとしてターゲット オブジェクトの Add メソッドを呼び出し、呼び出しごとに通常のオーバーロード解決を適用します。したがって、コレクション オブジェクトには、要素の初期化子ごとに適用可能な Add メソッドが含まれている必要があります

残念ながら、テキストは適用可能な Add メソッドが何であるかについての詳細には触れていませんが、明示的に実装されたインターフェイス メソッドは本質的に非公開と見なされるため、法案に適合しないようです (13.4.1 を参照)。

メソッド呼び出し、プロパティ アクセス、またはインデクサー アクセスで、完全修飾名を使用して明示的なインターフェイス メンバーの実装にアクセスすることはできません。明示的なインターフェイス メンバーの実装は、インターフェイス インスタンスを介してのみアクセスでき、その場合は単にそのメンバー名によって参照されます。

...

明示的なインターフェイス メンバーの実装には、他のメンバーとは異なるアクセシビリティ特性があります。明示的なインターフェイス メンバーの実装は、メソッド呼び出しまたはプロパティ アクセスで完全修飾名を介してアクセスできないため、ある意味で非公開です。ただし、インターフェイス インスタンスを介してアクセスできるため、ある意味ではパブリックでもあります。

于 2011-05-06T11:35:33.153 に答える
2

まず第一に、あなたはスポットです。はIDictionary<string,object>明示的に実装されています。

キャストする必要さえありません。これは機能します:

IDictionary<string,object> exdict = new ExpandoObject() 

コレクション構文が機能しない理由は、これがDictionary<T,T> コンストラクターでの実装であり、インターフェイスの一部ではないため、expando では機能しないためです。

上記の間違ったステートメント。そうです、追加機能を使用します:

static void Main(string[] args)
{
Dictionary<string,object> dictionary = new Dictionary<string, object>()
                                                {
                                                    {"Ali", "Ostad"}
                                                };
}

にコンパイルされます

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       27 (0x1b)
  .maxstack  3
  .locals init ([0] class [mscorlib]System.Collections.Generic.Dictionary`2<string,object> dictionary,
           [1] class [mscorlib]System.Collections.Generic.Dictionary`2<string,object> '<>g__initLocal0')
  IL_0000:  nop
  IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,object>::.ctor()
  IL_0006:  stloc.1
  IL_0007:  ldloc.1
  IL_0008:  ldstr      "Ali"
  IL_000d:  ldstr      "Ostad"
  IL_0012:  callvirt   instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,object>::Add(!0,
                                                                                                                 !1)
  IL_0017:  nop
  IL_0018:  ldloc.1
  IL_0019:  stloc.0
  IL_001a:  ret
} // end of method Program::Main

アップデート

主な理由は( になる修飾子なしで)Addとして実装されていることです。protectedprotected

Addに表示されないためExpandoObject、上記のように呼び出すことはできません。

于 2011-05-06T11:11:20.710 に答える