2011-12-06 5 views
3

DynamicObjectのドキュメントには、DynamicDictionaryの例があります。この例では、プロパティを持つクラスであるかのように辞書を扱うことができます。ここでオブジェクト初期化子をサポートするカスタムDynamicObjectクラスを書く方法

は(簡潔にするためにわずかに変更された)クラスである:私がやりたいのは何

public class DynamicDictionary : DynamicObject 
{ 
    Dictionary<string, object> _dictionary = new Dictionary<string, object>(); 

    public int Count 
    { 
     get { return _dictionary.Count; } 
    } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     string name = binder.Name.ToLower(); 
     return _dictionary.TryGetValue(name, out result); 
    } 

    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     _dictionary[binder.Name.ToLower()] = value; 
     return true; 
    } 
} 

は、私は次の操作を行うことができるように、クラスを変更です:

public class Test 
{ 
    public Test() 
    { 
     var result = Enumerable.Range(1, 5).Select(i => new DynamicDictionary 
     { 
      Id = i, 
      Foo = "Foo", 
      Bar = 2 
     }); 
    } 
} 

質問

  1. これは可能ですか?
  2. はいの場合、どうですか?
+0

オブジェクトイニシャライザはダイナミックオブジェクトでは機能しません – Magnus

+0

@Magnusは技術的にはダイナミックオブジェクトで動作しますが、ダイナミックではありません。したがって、あなたの動的オブジェクトが非動的な 'Id'プロパティを持っている場合は、オブジェクト初期化子を使用することができます。しかし、これは質問に答えるのに役立つものではありません。 – svick

+0

True、 "normal"プロパティの場合はうまく動作します。私はあなたが 'IEnumerable >'を取り、それを使ってディクショナリを作成するコンストラクタを追加すると思います。 – Magnus

答えて

0

Linqの組み込みのToDictionary()メソッドを使って私の問題を解決することができました。

例:私はこのような埋め込み言語のパターンを見ると

public Test() 
{ 
    var data = Enumerable.Range(1, 5).Select(i => new 
    { 
     Id = i, 
     Foo = "Foo", 
     Bar = 2 
    }); 
    var result = data 
     .Select(d => d.GetType().GetProperties() 
      .Select(p => new { Name = p.Name, Value = p.GetValue(pd, null) }) 
      .ToDictionary(
       pair => pair.Name, 
       pair => pair.Value == null ? string.Empty : pair.Value.ToString())); 
} 
4

DynamicObjectは、TryCreateInstance()を提供します。これは、このような状況を想定していますが、C#では使用できません。

私は、この周りにいくつかの方法を参照してください。

  1. は、動的なファクトリクラスを作成します。名前付きargumetsとのCreate()メソッドを呼び出すと、それは辞書にそれを渡します。

    class DynamicDictionaryFactory : DynamicObject 
    { 
        public override bool TryInvokeMember(
         InvokeMemberBinder binder, object[] args, out object result) 
        { 
         if (binder.Name == "Create") 
         { 
          // use binder.CallInfo.ArgumentNames and args 
          // to create the dynamic dictionary 
          result = …; 
          return true; 
         } 
    
         return base.TryInvokeMember(binder, args, out result); 
        } 
    } 
    
    … 
    
    dynamic factory = new DynamicDictionaryFactory(); 
    
    dynamic dict = factory.Create(Id: 42); 
    
  2. 使用非動的コレクション初期化子。たぶんあなたは尋ねたものに最も近いネストされたオブジェクト初期化子を使用することです

    // has to implement IEnumerable, so that collection initializer works 
    class DynamicDictionary 
        : DynamicObject, IEnumerable<KeyValuePair<string, object>> 
    { 
        public void Add(string name, object value) 
        { 
         m_dictionary.Add(name, value); 
        } 
    
        // IEnumerable implmentation and actual DynamicDictionary code here 
    } 
    
    … 
    
    dynamic dict = new DynamicDictionary { { "Id", 42 } }; 
    
  3. :これは、コード内の文字列としてプロパティ名を有することを意味します。

    class DynamicDictionary : DynamicObject 
    { 
        private readonly IDictionary<string, object> m_expandoObject = 
         new ExpandoObject(); 
    
        public dynamic Values 
        { 
         get { return m_expandoObject; } 
        } 
    
        // DynamicDictionary implementation that uses m_expandoObject here 
    } 
    
    … 
    
    dynamic dict = new DynamicDictionary { Values = { Id = 42 } }; 
    
1

(nuget経由)、オープンソースImpromptuInterfaceを使用することがBuilder Syntaxを持っている:それは、クラスには、その特性がオブジェクト初期化子を使用して設定することができますdynamicプロパティ(たとえば、Values)を、持っていますされています。初期化構文の近くで何かできるようにします。具体的にあなたが

var result = Enumerable.Range(1, 5).Select(i => Build<DynamicDictionary>.NewObject 
    (
     Id: i, 
     Foo: "Foo", 
     Bar: 2 
    )); 

を行うことができImpromptuInterface.Dynamic含めた後、あまりにもあなたが<DynamicDictionary>をドロップする場合、それは本質的には同じものですImpromptuDictionaryを使用すること構文ページに記載されている他のオプションがあります。ビルドの構文については、sourceも参照できます。

0

、私は拡張メソッドを使用する傾向があるので、私は私の目標を達成するために、次のコードを書くことができます:

public Test() 
{ 
    var data = Enumerable.Range(1, 5).Select(i => new 
    { 
     Id = i, 
     Foo = "Foo", 
     Bar = 2 
    }.AsDynamicDictionary()); 
} 

それから、object(匿名型を含む)をDynamicDictionaryに変換するコードを使って拡張メソッドを定義します:

public static class DynamicDictionaryExtensions 
{ 
    public static DynamicDictionary AsDynamicDictionary(this object data) 
    { 
     if (data == null) throw new ArgumentNullException("data"); 
     return new DynamicDictionary(
       data.GetType().GetProperties() 
       .Where(p => p. && p.CanRead) 
       .Select(p => new {Name: p.Name, Value: p.GetValue(data, null)}) 
       .ToDictionary(p => p.Name, p => p.Value) 
     ); 
    } 
} 

IDictionary<string, object>を受け取るにはDynamicDictionaryにコンストラクタを実装する必要がありますが、これはケーキです。

+0

'p => p。 && p.CanRead'あなたはここに何か不足しているようです。 – svick

関連する問題