Как написать собственный класс DynamicObject, поддерживающий инициализаторы объектов

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

Вопрос

В документации для DynamicObject естьпример кода сгенерированного тега, который позволяет вам работать со словарем, как если бы это класс со свойствами.

Вот класс (слегка измененный для краткости):

родовое слово

Я бы хотел изменить класс, чтобы я мог делать следующее:

родовое слово

< sizesВопросы

  1. Возможно ли это?
  2. Если да, то как?
Это было полезно?

Решение 3

Оказывается, я смог решить мою проблему, используя встроенный метод GensacodicCode Linq.

Пример:

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() , которыйпредназначен для подобных ситуаций, но его нельзя использовать в C #.

Я вижу несколько способов обойти это:

  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 } };
    

Когда я вижу подобный образец встроенного языка, я обычно использую методы расширения, поэтому для достижения своей цели я могу написать следующий код:

родовое слово

Затем я определил бы метод расширения с кодом, чтобы преобразовать любой генерируемый кодовый код (включая анонимно типизированный) в генерирующий кодовый код:

родовое слово

Вам нужно будет реализовать конструктор в object, чтобы получить код DynamicDictionary, но это совсем несложно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top