我像这样创建了一个人的对象。
Person person=new Person("Sam","Lewis")
它具有以下属性。
person.Dob
person.Address
但是现在我想添加类似这样的属性,并在创建对象后在运行时设置值。 person.Age person.Sex
我如何在创建对象后添加这些额外的属性。这些属性名称可能会随时更改。因此无法硬编码“Age”和“Sex”。
我像这样创建了一个人的对象。
Person person=new Person("Sam","Lewis")
它具有以下属性。
person.Dob
person.Address
但是现在我想添加类似这样的属性,并在创建对象后在运行时设置值。 person.Age person.Sex
我如何在创建对象后添加这些额外的属性。这些属性名称可能会随时更改。因此无法硬编码“Age”和“Sex”。
对于“普通”对象而言这是不可能的,但你可以使用ExpandoObject
和dynamic
关键字来实现:
dynamic person = new ExpandoObject();
person.FirstName = "Sam";
person.LastName = "Lewis";
person.Age = 42;
person.Foo = "Bar";
...
如果你试图赋值一个不存在的属性,它会被添加到对象中。如果你试图读取一个不存在的属性,它将抛出异常。因此,这与字典的行为大致相同(实际上,ExpandoObject实现了IDictionary<string, object>
)。ExpandoObject
序列化为JSON,并得到了预期的结果。请参见https://gist.github.com/thomaslevesque/63a7ae1a8880a440bfe88334b5aa7c35。 - Thomas Levesque看一下ExpandoObject。
例如:
dynamic person = new ExpandoObject();
person.Name = "Mr bar";
person.Sex = "No Thanks";
person.Age = 123;
更多阅读请点击这里。
JsonExtensionData
属性。public class Pet
{
public string Name { get; set; }
public string Type { get; set; }
[JsonExtensionData]
public IDictionary<string, object> AdditionalData { get; set; }
}
那么你可以反序列化JSON:
public class Program
{
public static void Main()
{
var bingo = JsonConvert.DeserializeObject<Pet>("{\"Name\": \"Bingo\", \"Type\": \"Dog\", \"Legs\": 4 }");
Console.WriteLine(bingo.AdditionalData["Legs"]); // 4
var tweety = JsonConvert.DeserializeObject<Pet>("{\"Name\": \"Tweety Pie\", \"Type\": \"Bird\", \"CanFly\": true }");
Console.WriteLine(tweety.AdditionalData["CanFly"]); // True
tweety.AdditionalData["Color"] = "#ffff00";
Console.WriteLine(JsonConvert.SerializeObject(tweety)); // {"Name":"Tweety Pie","Type":"Bird","CanFly":true,"Color":"#ffff00"}
}
}
如果您不能使用dynamic类型与ExpandoObject,那么可以使用“属性包”机制,在其中使用字典(或其他键/值集合类型)存储字符串key
,用于命名属性和所需类型的value
。
请参见此处 以获取示例实现。
另一种实现方式是在调用ASP助手时使用它来组合参数:
public static object CombineObjects(this object item, object add)
{
var ret = new ExpandoObject() as IDictionary<string, Object>;
var props = item.GetType().GetProperties();
foreach (var property in props)
{
if (property.CanRead)
{
ret[property.Name]= property.GetValue(item);
}
}
props = add.GetType().GetProperties();
foreach (var property in props)
{
if (property.CanRead)
{
ret[property.Name] = property.GetValue(add);
}
}
return ret;
}
解决这个问题的另一个选择(取决于您的情况)是利用Newtonsoft.Json的ExpandoObjectConverter
JSON转换器类。
将对象序列化为JSON,然后使用转换器将其反序列化为dynamic
字段中的ExpandoObject
:
Person person = new Person("Sam", "Lewis");
var personJson = JsonConvert.SerializeObject(person);
dynamic personExpando =
JsonConvert.DeserializeObject<ExpandoObject>(personJson, new ExpandoObjectConverter());
personExpando.Dob = "1/1/1900";
personExpando.Address = "777 Pearly Gates Dr.";
{
"FirstName": "Sam",
"LastName": "Lewis",
"Dob": "1/1/1900",
"Address": "777 Pearly Gates Dr."
}
person
对象未更改;我们实际上没有改变该对象。看看 Clay 库:
它提供了类似于ExpandoObject的东西,但还带有许多额外的功能。这里是一篇博客文章,解释如何使用它:
http://weblogs.asp.net/bleroy/archive/2010/08/18/clay-malleable-c-dynamic-objects-part-2.aspx
(请务必阅读IPerson接口示例)
我不明白为什么有人想要在作为 DataTemplate
的 class
中动态添加新属性,根据数据的需要,你应该始终紧密定义 class
。
有些情况下,您可以使用 ExpandoObject
,但类型是在运行时解析的,没有人知道它具有哪些属性,这样会更容易出错。
您可以考虑将 property collection
视为更好的设计思路,其中您可以向 class
添加一个 Dictionary<string,Object>
并使用 indexer
来 get
/set
其值,如下所示:
public class Person
{
public string FirstName {get;set;}
public string LastName {get;set;}
public Dictionary<string,object> Fields; //propertyCollection
public Person(string firstName,string lastName) :base()
{
FirstName = firstName;
LastName = lastName;
Fields = new Dictionary<string,object>(); //initialize Fields
}
public object this[string name] //indexer to access Fields
{
get { return Fields[name]; }
set { Fields[name] = value; }
}
}
这将允许您添加任何新属性,如下:
var person = new Person("Sam","Lewis");
person["age"] = 10;
person["sex"] = "male";
MyClass varClass = new MyClass();
varClass.propObjectProperty = new { Id = 1, Description = "test" };
//if you need to treat the class as an object
var varObjectProperty = ((dynamic)varClass).propObjectProperty;
((dynamic)varClass).propObjectProperty = new { Id = varObjectProperty.Id, Description = varObjectProperty.Description, NewDynamicProperty = "new dynamic property description" };
//if your property is an object, instead
var varObjectProperty = varClass.propObjectProperty;
varClass.propObjectProperty = new { Id = ((dynamic)varObjectProperty).Id, Description = ((dynamic)varObjectProperty).Description, NewDynamicProperty = "new dynamic property description" };
使用这种方法,您基本上会重写对象属性,添加或删除属性,就像您首次创建该对象一样。
new { ... }
语法。
针对您的特定情况,最好创建一个实际对象,将“dob”和“address”等属性分配给它,就像它是一个人一样,处理结束时,将属性转移给实际的“Person”对象。