在运行时动态添加 C# 属性

Posted

技术标签:

【中文标题】在运行时动态添加 C# 属性【英文标题】:Dynamically Add C# Properties at Runtime 【发布时间】:2013-03-27 00:43:00 【问题描述】:

我知道有一些问题可以解决这个问题,但答案通常遵循推荐字典或参数集合的思路,这在我的情况下不起作用。

我正在使用一个通过反射工作的库来对具有属性的对象做很多聪明的事情。这适用于已定义的类以及动态类。我需要更进一步,并按照以下方式做一些事情:

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 派生允许您提出自己的策略来处理这些动态成员请求,注意这里有怪物:编译器将能够验证很多动态调用,你不会得到智能感知,所以请记住这一点。

【讨论】:

【参考方案2】:

感谢@Clint 的精彩回答:

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

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

【讨论】:

这里的属性是什么“foreach(属性中的var属性)”例如我有一个学生班级,我想根据我的 JSON 响应添加属性 @singhswat 它是Dictionary&lt;string, object&gt;(基于问题中的代码)。【参考方案3】:

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

var jsonString = @"";

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

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

Console.WriteLine(JsonSerializer.Serialize(jsonDoc));

【讨论】:

以上是关于在运行时动态添加 C# 属性的主要内容,如果未能解决你的问题,请参考以下文章

C#自定义控件中如何动态添加属性

C# WinForm 自定义控件如何实现动态添加子控件

在运行时(动态)将 EditorAttribute 添加到对象的特殊属性

C# 动态添加的属性与 datagridview 顺序混淆

C#动态给treeview控件添加节点和子节点

如何向动态创建的 (C#) 元素添加“必需”属性?