在运行时动态添加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;

}

该库可以很好地与动态变量类型配合使用,并具有手动分配的属性。但是我不知道将要预先添加多少个属性。

Answers:


105

您是否看过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派生而来的是,您可以提出自己的策略来处理这些动态成员请求,请注意此处存在怪兽:编译器将无法验证您的许多动态调用,并且您不会得到智能感知,因此只需保持记住这一点。


38

感谢@Clint的出色回答:

只是想强调使用Expando Object解决这个问题有多么容易:

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

10
+1。备注:为什么不返回Dictionary而不是dynamic?(至少是IDictionary)?我的意思是,返回动态有点“误导”,因为您总是会返回字典。
Veverke

答案已被编辑,使Veverke的评论陈旧。
DharmaTurtle

3

您可以将json字符串反序列化为字典,然后添加新属性,然后对其进行序列化。

 var jsonString = @"{}";

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

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

        Console.WriteLine(JsonSerializer.Serialize(jsonDoc));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.