DynamicObject и ExpandoObject

70

Что, если необходимо создать собственный динамический объект? Для этого на выбор доступно два варианта: наследование от DynamicObject либо использование ExpandoObject. Использование DynamicObject требует немного больше работы, поскольку придется переопределить несколько методов. ExpandoObject представляет собой запечатанный (sealed) класс, готовый к применению.

DynamicObject

Рассмотрим объект, представляющий пользователя. Обычно при этом должны определяться свойства для имени и возраста. Теперь предположим, что необходимо иметь возможность строить такой объект во время выполнения, на основе системы, не имеющей предварительного представления о том, какие свойства могут быть у объекта, и какие методы он может поддерживать. Это именно то, что может обеспечить объект, основанный на DynamicObject. Такая функциональность требуется очень редко, но до настоящего времени язык C# не позволял ее реализовать.

Для начала посмотрим, как выглядит DynamicObject:

using System;
using System.Dynamic;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class MyDynamicObject : DynamicObject
    {
        Dictionary _dynamic = new Dictionary();
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            bool qq = false;
            result = null;
            if (_dynamic.ContainsKey(binder.Name))
            {
                result = _dynamic[binder.Name];
                qq = true;
            }
            else
            {
                result = "Свойство не найдено!";
                qq = false;
            }
            return qq;
        }

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

        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
        {
            dynamic method = _dynamic[binder.Name];
            result = method((DateTime)args[0]);
            return result != null;
        }
    }

    class Program
    {
        static void Main()
        {
        }
    }
}

В этом примере переопределяются три метода: TrySetMember, TryGetMember и TryInvokeMember.

TrySetMember добавляет новый метод, свойство или поле к объекту. В данном примере информация о членах сохраняется в объекте Dictionary. Объект SetMemberBinder, переданный в TrySetMember, содержит свойство Name, которое используется для идентификации элемента в Dictionary.

TryGetMember извлекает объект, хранящийся в Dictionary, на основе свойства Name из GetMemberBinder.

ExpandoObjeсt

Объект ExpandoObject работает аналогично DynamicObject, который был создан в предыдущем примере. Отличие в том, что никаких методов переопределять не понадобится.

Если нужно управлять добавлением и обращением к свойствам динамического объекта, то наилучшим выбором будет наследование от DynamicObject. Вместе с DynamicObject можно использовать несколько методов для переопределения и точного контроля того, как объект взаимодействует с исполняющей средой. Для прочих случаев подойдет тип dynamic или ExpandoObject.

Пройди тесты
Лучший чат для C# программистов