我像这样创建人物对象。
Person person=new Person("Sam","Lewis")
它有这样的属性。
person.Dob
person.Address
但现在我想添加这样的属性,并在创建对象后在运行时设置值。 人士 person.Sex
如何在创建对象后添加这些额外属性。那些属性名称可以不时更改。因此,不能硬编码“年龄”和“性别”。
答案 0 :(得分:48)
使用“普通”对象是不可能的,但您可以使用ExpandoObject
和dynamic
关键字来执行此操作:
dynamic person = new ExpandoObject();
person.FirstName = "Sam";
person.LastName = "Lewis";
person.Age = 42;
person.Foo = "Bar";
...
如果尝试分配不存在的属性,则会将其添加到对象中。如果您尝试读取不存在的属性,则会引发异常。所以它与字典大致相同(而ExpandoObject实际上实现了IDictionary<string, object>
)
答案 1 :(得分:8)
例如:
dynamic person = new ExpandoObject();
person.Name = "Mr bar";
person.Sex = "No Thanks";
person.Age = 123;
补充阅读here。
答案 2 :(得分:8)
如果你不能将dynamic类型与ExpandoObject一起使用,那么你可以使用'Property Bag'机制,其中,使用字典(或其他一些键/值集合类型)你存储字符串key
,用于命名所需类型的属性和value
。
答案 3 :(得分:4)
如果您仅需要用于JSON序列化/反序列化的动态属性,例如,如果您的API根据上下文接受具有不同字段的JSON对象,则可以使用Newtonsoft.Json或System中可用的JsonExtensionData
属性。 Text.Json。
示例:
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"}
}
}
答案 4 :(得分:2)
考虑使用装饰器模式http://en.wikipedia.org/wiki/Decorator_pattern
您可以在运行时使用在事件发生时具有不同属性的装饰器更改装饰器。
答案 5 :(得分:0)
看看Clay图书馆:
它提供类似于ExpandoObject的东西,但有一些额外的功能。以下是解释如何使用它的博客文章:
http://weblogs.asp.net/bleroy/archive/2010/08/18/clay-malleable-c-dynamic-objects-part-2.aspx
(务必阅读IPerson界面示例)
答案 6 :(得分:0)
如果您的类具有对象属性,或者您的属性实际上已强制转换为对象,则可以通过重新分配其属性来重塑对象,如:
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”,就好像它是一个人一样,然后在过程结束时将这些属性转移到实际的“人”对象。
答案 7 :(得分:0)
另一种实现,在调用 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;
}