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

89

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

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

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;

}

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

Пол Гримшоу
источник

Ответы:

105

Вы смотрели ExpandoObject?

см. http://blogs.msdn.com/b/csharpfaq/archive/2009/10/01/dynamic-in-c-4-0-introduction-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, поэтому просто продолжайте это в виду.

Клинт
источник
39

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

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

    var dynamicObject = new ExpandoObject() as IDictionary<string, Object>;
    foreach (var property in properties) {
        dynamicObject.Add(property.Key,property.Value);
    }
Пол Гримшоу
источник
3

вы можете десериализовать свою строку json в словарь, а затем добавить новые свойства, а затем сериализовать ее.

 var jsonString = @"{}";

        var jsonDoc = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonString);

        jsonDoc.Add("Name", "Khurshid Ali");

        Console.WriteLine(JsonSerializer.Serialize(jsonDoc));
Хуршид Али
источник