C# 向现有对象动态添加属性

C# 向现有对象动态添加属性,c#,C#,我像这样创建person对象 Person person=new Person("Sam","Lewis") person.Dob person.Address 它有这样的属性 Person person=new Person("Sam","Lewis") person.Dob person.Address 但是现在我想添加这样的属性,并在创建对象后的运行时设置值。 人.年龄 人,性 如何在创建对象后添加这些额外属性。这些属性名称可以随时更改。因此,不能硬编码“年龄”和“性别”。

我像这样创建person对象

 Person person=new Person("Sam","Lewis") 
person.Dob
person.Address
它有这样的属性

 Person person=new Person("Sam","Lewis") 
person.Dob
person.Address
但是现在我想添加这样的属性,并在创建对象后的运行时设置值。 人.年龄 人,性

如何在创建对象后添加这些额外属性。这些属性名称可以随时更改。因此,不能硬编码“年龄”和“性别”。

使用“正常”对象是不可能的,但可以使用
ExpandoObject
dynamic
关键字:

dynamic person = new ExpandoObject();
person.FirstName = "Sam";
person.LastName = "Lewis";
person.Age = 42;
person.Foo = "Bar";
...
如果尝试指定不存在的属性,则该属性将添加到对象中。如果尝试读取不存在的属性,它将引发异常。因此,它的行为与dictionary大致相同(ExpandoObject实际上实现了
IDictionary

看一下

例如:

dynamic person = new ExpandoObject();
person.Name = "Mr bar";
person.Sex = "No Thanks";
person.Age = 123;
附加阅读。

如果不能将该类型与一起使用,则可以使用“属性包”机制,在该机制中,使用字典(或其他一些键/值集合类型)存储字符串
,该字符串命名所需类型的属性和


请参阅。

查看粘土库:

它提供了类似于ExpandoObject的东西,但是有一些额外的特性。以下是解释如何使用它的博客帖子:


(请务必阅读IPerson接口示例)

考虑使用装饰器模式


当事件发生时,您可以在运行时使用具有不同属性的装饰器来更改装饰器。

如果您的类具有对象属性,或者如果您的属性实际强制转换为对象,则可以通过重新指定其属性来重塑对象,如中所示:

  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分配给它,并在过程结束时将属性转移到实际的“person”对象。

如果您只需要JSON序列化/反序列化的动态属性,例如,如果API根据上下文接受具有不同字段的JSON对象,则可以使用Newtonsoft.JSON或System.Text.JSON中提供的
JsonExtensionData
属性

例如:

public class Pet
{
    public string Name { get; set; }
    public string Type { get; set; }

    [JsonExtensionData]
    public IDictionary<string, object> AdditionalData { get; set; }
}
公共级宠物
{
公共字符串名称{get;set;}
公共字符串类型{get;set;}
[JsonExtensionData]
公共IDictionary附加数据{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"}
    }
}
公共类程序
{
公共静态void Main()
{
var bingo=JsonConvert.DeserializeObject(“{“Name\”:“bingo\”,“Type\”:“Dog\”,“Legs\”:4}”);
Console.WriteLine(bingo.AdditionalData[“Legs”]);//4
var tweety=JsonConvert.DeserializeObject(“{”Name\“:\“tweety Pie\”,“Type\”:“Bird\”,“CanFly\”:true}”);
Console.WriteLine(tweety.AdditionalData[“CanFly”]);//True
tweety.AdditionalData[“Color”]=“#ffff00”;
Console.WriteLine(JsonConvert.SerializeObject(tweety));//{“名称”:“tweety派”,“类型”:“Bird”,“CanFly”:true,“Color”:“#ffff00”}
}
}

另一个实现,在调用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;
    }
公共静态对象组合对象(此对象项,对象添加)
{
var ret=作为IDictionary的新ExpandooObject();
var props=item.GetType().GetProperties();
foreach(props中的var属性)
{
if(property.CanRead)
{
ret[property.Name]=property.GetValue(项);
}
}
props=add.GetType().GetProperties();
foreach(props中的var属性)
{
if(property.CanRead)
{
ret[property.Name]=property.GetValue(add);
}
}
返回ret;
}

这应该会有帮助,我希望能重复感谢您的回复。我的问题是运行时只有我得到属性名。作为您的示例FirstName、LastName、Age、Foo,我必须知道如何实现这些属性。我从表中获取属性名称,我需要从中创建属性。@Sanjeewa,在这种情况下,您最好使用
字典
<如果您在运行前不知道属性名,那么代码>扩展对象
将不会有很大帮助。那么我可以使用icustomtypedescriptor吗?真的吗?它不能通过反射来实现吗?在我的例子中,ExpandoObject不是一个选项,因为它实际上是一个以字典结构存储属性的对象。这个问题是,当序列化为JSON时,结果是一个数组数组,这与纯对象属性的JSON表示非常不同。你知道如何解决这个问题吗?当然,如果不手工创建JSON字符串,@jstualdo,不,就不可能向现有对象添加属性;C#是一种静态类型的语言,而不是像JavaScript那样的动态语言。但我不知道你说的JSON序列化是什么意思。我刚刚尝试将一个
ExpandoObject
序列化为JSON,它给出了预期的结果。看这不是问题的答案,而是非常有用的信息