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


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

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

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;

}

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

2 66

2 ответа:

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

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

от MSDN:

класс ExpandoObject позволяет добавлять и удалять элементы его экземпляров во время выполнения, а также устанавливать и получать значения этих элементов. Этот класс поддерживает динамическое связывание, что позволяет использовать стандартный синтаксис, например sampleObject.пробоотборник вместо более сложного синтаксиса, такого как 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, так что просто имейте это в виду.

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

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

    var dynamicObject = new ExpandoObject() as IDictionary<string, Object>;
    foreach (var property in properties) {
        dynamicObject.Add(property.Key,property.Value);
    }