Динамически добавлять свойства С# во время выполнения

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

Я использую библиотеку, которая работает через отражение, чтобы делать много умных вещей с объектами со свойствами. Это работает с определенными классами, а также с динамическими классами. Мне нужно сделать еще один шаг и сделать что-то в этом направлении:

public static object GetDynamicObject(Dictionary<string,object> properties) {
    var myObject = new object();
    foreach (var property in properties) {
        //This next line obviously doesn't work... 
        myObject.AddProperty(property.Key,property.Value);
    }
    return myObject;
}

public void Main() {
    var properties = new Dictionary<string,object>();
    properties.Add("Property1",aCustomClassInstance);
    properties.Add("Property2","TestString2");

    var myObject = GetDynamicObject(properties);

    //Then use them like this (or rather the plug in uses them through reflection)
    var customClass = myObject.Property1;
    var myString = myObject.Property2;

}

Библиотека отлично работает с типом динамической переменной, свойства которой назначены вручную. Однако я не знаю, сколько или каких свойств будет добавлено заранее.

Ответ 1

Вы взглянули на ExpandoObject?

см. http://blogs.msdn.com/b/csharpfaq/archive/2009/10/01/dynamic-in-c-4-0-introducing-the-expandoobject.aspx

Из MSDN:

Класс ExpandoObject позволяет добавлять и удалять члены своих экземпляров во время выполнения, а также устанавливать и получать значения этих членов. Этот класс поддерживает динамическое связывание, которое позволяет использовать стандартный синтаксис, например sampleObject.sampleMember, вместо более сложного синтаксиса типа sampleObject.GetAttribute( "sampleMember" ).

Позволяет вам делать такие классные вещи, как:

dynamic dynObject = new ExpandoObject();
dynObject.SomeDynamicProperty = "Hello!";
dynObject.SomeDynamicAction = (msg) =>
    {
        Console.WriteLine(msg);
    };

dynObject.SomeDynamicAction(dynObject.SomeDynamicProperty);

В зависимости от вашего фактического кода вас может больше заинтересовать:

public static dynamic GetDynamicObject(Dictionary<string, object> properties)
{
    return new MyDynObject(properties);
}

public sealed class MyDynObject : DynamicObject
{
    private readonly Dictionary<string, object> _properties;

    public MyDynObject(Dictionary<string, object> properties)
    {
        _properties = properties;
    }

    public override IEnumerable<string> GetDynamicMemberNames()
    {
        return _properties.Keys;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (_properties.ContainsKey(binder.Name))
        {
            result = _properties[binder.Name];
            return true;
        }
        else
        {
            result = null;
            return false;
        }
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        if (_properties.ContainsKey(binder.Name))
        {
            _properties[binder.Name] = value;
            return true;
        }
        else
        {
            return false;
        }
    }
}

Таким образом вам просто нужно:

var dyn = GetDynamicObject(new Dictionary<string, object>()
    {
        {"prop1", 12},
    });

Console.WriteLine(dyn.prop1);
dyn.prop1 = 150;

Вывод из DynamicObject позволяет вам разработать собственную стратегию для обработки этих динамических запросов членов, Остерегайтесь монстров здесь: компилятор не сможет проверить много ваших динамических вызовов, и вы не получите intellisense, поэтому просто имейте это в виду.

Ответ 2

Спасибо @Clint за отличный ответ:

Просто хотел подчеркнуть, насколько легко было решить это с помощью объекта Expando:

public static dynamic GetDynamicObject(Dictionary<string,object> properties) {
    var dynamicObject = new ExpandoObject() as IDictionary<string, Object>;
    foreach (var property in properties) {
        dynamicObject.Add(property.Key,property.Value);
    }
    return dynamicObject;
}