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


}

该库可以很好地使用动态变量类型,并手动分配属性。然而,我不知道有多少或什么属性将事先添加。

221158 次浏览

Have you taken a look at ExpandoObject?

see: https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject

From MSDN:

The ExpandoObject class enables you to add and delete members of its instances at run time and also to set and get values of these members. This class supports dynamic binding, which enables you to use standard syntax like sampleObject.sampleMember instead of more complex syntax like sampleObject.GetAttribute("sampleMember").

Allowing you to do cool things like:

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


dynObject.SomeDynamicAction(dynObject.SomeDynamicProperty);

Based on your actual code you may be more interested in:

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;
}
}
}

That way you just need:

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


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

Deriving from DynamicObject allows you to come up with your own strategy for handling these dynamic member requests, beware there be monsters here: the compiler will not be able to verify a lot of your dynamic calls and you won't get intellisense, so just keep that in mind.

Thanks @Clint for the great answer:

Just wanted to highlight how easy it was to solve this using the Expando Object:

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

you could deserialize your json string into a dictionary and then add new properties then serialize it.

var jsonString = @"{}";


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


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


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