4

DynamicObjectのドキュメントには、DynamicDictionaryプロパティを持つクラスであるかのようにディクショナリを操作できるa の例があります。

クラスは次のとおりです(簡潔にするためにわずかに変更されています):

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. はいの場合、どのように?
4

4 に答える 4

4

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

私はこれを回避するいくつかの方法を見ます:

  1. 動的ファクトリクラスを作成します。Create()名前付きargumetsを使用してそのメソッドを呼び出すと、ディクショナリに渡されます。

    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. おそらくあなたが求めたものに最も近いのは、ネストされたオブジェクト初期化子を使用することでしょう。つまり、クラスにはdynamicプロパティ(たとえばValues)があり、そのプロパティはオブジェクト初期化子を使用して設定できます。

    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 } };
    
于 2011-12-06T23:52:29.980 に答える
1

オープンソースの ImpromptuInterface を (nuget 経由で) 使用すると、Builder Syntaxがあります。これにより、初期化構文に近いことができます。具体的には、ImpromptuInterface.Dynamicあなたができることを含めた後

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

をドロップすると、その構文ページにリストされている他のオプションもあり、本質的に同じもの<DynamicDictionary>を使用します。ImpromptuDictionaryまた、ビルド構文のソースも確認できます。

于 2011-12-08T13:53:55.440 に答える
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)
        );
    }
}

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

于 2013-07-14T09:43:22.880 に答える
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()));
}
于 2011-12-22T00:28:04.823 に答える