كيفية كتابة فئة ديناميكوبجيكت مخصصة التي تدعم التهيئة الكائن

StackOverflow https://stackoverflow.com/questions/8408403

سؤال

في وثائق ل ديناميكوبجيكت, ، هناك مثال على أ DynamicDictionary يتيح لك ذلك العمل مع قاموس كما لو كان فصلا ذا خصائص.

هنا هو الطبقة (تعديل طفيف للإيجاز):

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. اذا نعم, كيف?
هل كانت مفيدة؟

المحلول 3

اتضح ، وكنت قادرا على حل مشكلتي باستخدام لينق المدمج في 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()));
}

نصائح أخرى

DynamicObject يوفر TryCreateInstance(), ، وهو مخصص لحالات مثل هذه ، لكنه غير قابل للاستخدام من ج#.

أرى بعض الطرق حول هذا:

  1. إنشاء فئة مصنع ديناميكية.عند استدعاء لها 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. ربما يكون الأقرب إلى ما طلبته هو استخدام متداخلة كائن مهيئ.وهذا هو ، فإن الطبقة لديها 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 } };
    

When I see a pattern of embedded language like this, I tend to use extension methods, so I could write the following code to achieve my goal:

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

Then I would define the extension method with the code to convert any object (including anonymously typed ones) to 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)
        );
    }
}

You would have to implement a constructor in DynamicDictionary to receive a IDictionary<string, object>, but that's a piece of cake.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top