54

I create the person object like this.

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

It has properties like this.

person.Dob
person.Address

But now I want to add properties like this and set the values at the run time after creating the object. person.Age person.Sex

How can I add those extra properties after creating the object. Those property name can be changed time to time. Therefor can't hardcode the "Age" and "Sex".

Carlos Landeras
  • 10,812
  • 11
  • 54
  • 82
Snj
  • 773
  • 3
  • 7
  • 19
  • This should help, i hope http://www.gamedev.net/topic/396996-c-adding-properties-to-objects-at-runtime/ – Zenwalker Jun 13 '11 at 10:59
  • possible duplicate of [Adding properties dynamically to a class](http://stackoverflow.com/questions/6196022/adding-properties-dynamically-to-a-class) – nawfal Jul 20 '14 at 06:17

8 Answers8

81

It's not possible with a "normal" object, but you can do it with an ExpandoObject and the dynamic keyword:

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

If you try to assign a property that doesn't exist, it is added to the object. If you try to read a property that doesn't exist, it will raise an exception. So it's roughly the same behavior as a dictionary (and ExpandoObject actually implements IDictionary<string, object>)

Thomas Levesque
  • 278,830
  • 63
  • 599
  • 738
  • 1
    Thanks for the reply. My problem is run time only I get the property names. As your example FirstName, LastName,Age, Foo I must know to implement the properties. I get property names from the table and I need to create properties from that. – Snj Jun 14 '11 at 10:27
  • 4
    @Sanjeewa, in that case your best bet is probably to use a `Dictionary`. `ExpandoObject` won't be very helpful if you don't know the property names before runtime. – Thomas Levesque Jun 14 '11 at 11:24
  • Then can I use icustomtypedescriptor for that – Snj Jun 16 '11 at 09:56
  • Really? cannot it be made by using Reflection? in my case, ExpandoObject is not an option because it is really an object that stores properties as a dictionary structure. This has the problem that when serializing to JSON, result is an array of arrays, which is very different from the JSON representation of a pure object properties.Any idea of how to solve this? without creating JSON string by hand, of course, – jstuardo Dec 22 '17 at 23:11
  • 1
    @jstuardo, no, it's really not possible to add properties to an existing object; C# is a statically typed language, not a dynamic language like JavaScript. But I'm not sure what you mean about JSON serialization. I just tried serializing an `ExpandoObject` to JSON, and it gave the expected result. See https://gist.github.com/thomaslevesque/63a7ae1a8880a440bfe88334b5aa7c35 – Thomas Levesque Dec 23 '17 at 12:04
  • Thomas Levesque a dictionary serialization is different from pure object serialization. I have finally built Json manually using Newtonsoft library... that way I returned a ContentResult to the view. – jstuardo Dec 25 '17 at 20:12
  • @jstuardo then I don't know what you call "pure object serialization". In JSON objects are basically dictionaries... – Thomas Levesque Dec 26 '17 at 08:27
13

Take a look at the ExpandoObject.

For example:

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

Additional reading here.

George Duckett
  • 30,870
  • 7
  • 96
  • 158
10

If you only need the dynamic properties for JSON serialization/deserialization, eg if your API accepts a JSON object with different fields depending on context, then you can use the JsonExtensionData attribute available in Newtonsoft.Json or System.Text.Json.

Example:

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

    [JsonExtensionData]
    public IDictionary<string, object> AdditionalData { get; set; }
}

Then you can deserialize 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"}
    }
}
warrickh
  • 1,566
  • 1
  • 15
  • 14
10

If you can't use the dynamic type with ExpandoObject, then you could use a 'Property Bag' mechanism, where, using a dictionary (or some other key / value collection type) you store string key's that name the properties and values of the required type.

See here for an example implementation.

Grant Thomas
  • 43,307
  • 9
  • 83
  • 125
2

Consider using the decorator pattern http://en.wikipedia.org/wiki/Decorator_pattern

You can change the decorator at runtime with one that has different properties when an event occurs.

2

Another implementation, using it to combine parameters when calling ASP helpers:

    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;
    }
Nick Kovalsky
  • 3,884
  • 20
  • 42
0

Take a look at the Clay library:

http://clay.codeplex.com/

It provides something similar to the ExpandoObject but with a bunch of extra features. Here is blog post explaining how to use it:

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

(be sure to read the IPerson interface example)

santi
  • 467
  • 2
  • 4
  • 10
0

If you have a class with an object property, or if your property actually casts to an object, you can reshape the object by reassigning its properties, as in:

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

With this approach, you basically rewrite the object property adding or removing properties as if you were first creating the object with the

new { ... }

syntax.

In your particular case, you're probably better off creating an actual object to which you assign properties like "dob" and "address" as if it were a person, and at the end of the process, transfer the properties to the actual "Person" object.

Itaca
  • 31
  • 6