【问题标题】:Dynamically add properties to a existing object将属性动态添加到现有对象
【发布时间】:2011-06-13 10:55:29
【问题描述】:

我这样创建 person 对象。

 Person person=new Person("Sam","Lewis") 

它有这样的属性。

person.Dob
person.Address

但现在我想添加这样的属性并在创建对象后在运行时设置值。 人士 人.性别

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

【问题讨论】:

标签: c#


【解决方案1】:

使用“普通”对象是不可能的,但您可以使用 ExpandoObjectdynamic 关键字来做到这一点:

dynamic person = new ExpandoObject();
person.FirstName = "Sam";
person.LastName = "Lewis";
person.Age = 42;
person.Foo = "Bar";
...

如果您尝试分配不存在的属性,则会将其添加到对象中。如果您尝试读取一个不存在的属性,它将引发异常。所以它与字典的行为大致相同(ExpandoObject 实际上实现了IDictionary<string, object>

【讨论】:

  • 感谢您的回复。我的问题是运行时只有我得到属性名称。作为您的示例 FirstName, LastName,Age, Foo 我必须知道要实现这些属性。我从表中获取属性名称,我需要从中创建属性。
  • @Sanjeewa,在这种情况下,您最好的选择可能是使用Dictionary<string, object>ExpandoObject 如果您在运行前不知道属性名称,将不会很有帮助。
  • 那我可以使用 icustomtypedescriptor 吗
  • 真的吗?不能用反射来制作吗?就我而言,ExpandoObject 不是一个选项,因为它实际上是将属性存储为字典结构的对象。这有一个问题,当序列化为 JSON 时,结果是一个数组数组,这与纯对象属性的 JSON 表示非常不同。知道如何解决这个问题吗?当然,无需手动创建 JSON 字符串,
  • @jstuardo,不,实际上不可能向现有对象添加属性; C# 是一种静态类型语言,而不是像 JavaScript 这样的动态语言。但我不确定你对 JSON 序列化的意思。我刚刚尝试将ExpandoObject 序列化为 JSON,它给出了预期的结果。见gist.github.com/thomaslevesque/63a7ae1a8880a440bfe88334b5aa7c35
【解决方案2】:

看看ExpandoObject

例如:

dynamic person = new ExpandoObject();
person.Name = "Mr bar";
person.Sex = "No Thanks";
person.Age = 123;

补充阅读here.

【讨论】:

    【解决方案3】:

    如果您不能将dynamic 类型与ExpandoObject 一起使用,那么您可以使用“属性包”机制,其中使用字典(或其他一些键/值集合类型)存储字符串@987654324用于命名属性的 @ 和所需类型的 values。

    here for an example implementation

    【讨论】:

      【解决方案4】:

      如果您只需要 JSON 序列化/反序列化的动态属性,例如,如果您的 API 根据上下文接受具有不同字段的 JSON 对象,那么您可以使用 Newtonsoft.Json 或 System.Text 中的JsonExtensionData 属性。 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"}
          }
      }
      

      【讨论】:

      • 这不是问题的答案,而是非常有用的信息
      【解决方案5】:

      考虑使用装饰器模式http://en.wikipedia.org/wiki/Decorator_pattern

      您可以在运行时将装饰器更改为在事件发生时具有不同属性的装饰器。

      【讨论】:

        【解决方案6】:

        另一种实现,在调用 ASP helper 时使用它来组合参数:

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

        【讨论】:

          【解决方案7】:

          看看 Clay 库:

          http://clay.codeplex.com/

          它提供了与 ExpandoObject 类似的东西,但有很多额外的功能。这是解释如何使用它的博客文章:

          http://weblogs.asp.net/bleroy/archive/2010/08/18/clay-malleable-c-dynamic-objects-part-2.aspx

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

          【讨论】:

            【解决方案8】:

            如果您有一个具有对象属性的类,或者如果您的属性实际上转换为一个对象,您可以通过重新分配其属性来重塑该对象,如下所示:

              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”对象。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2012-01-12
              • 1970-01-01
              • 2011-10-05
              • 2017-10-14
              • 2016-05-04
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多