Adding Unknown (At Design Time) Properties to an Expandoobject

Adding unknown (at design time) properties to an ExpandoObject

I wondered how it might be possible to add members to a class "on the fly" and came up with this sample:

using System;
using System.Collections.Generic;
using System.Dynamic;

class Program
{
static void Main()
{
dynamic expando = new ExpandoObject();
var p = expando as IDictionary<String, object>;

p["A"] = "New val 1";
p["B"] = "New val 2";

Console.WriteLine(expando.A);
Console.WriteLine(expando.B);
}
}

The point of this code snippet is that the members A and B are defined as string literals (hard coded/stringified) in and added via ExpandoObject's IDictionary interface. We test for the keys' existence and values (and prove the concept) by accessing them directly and outputting to console.

Add property to ExpandoObject with the same name as a string

ExpandoObject implements IDictionary<string, object>:

((IDictionary<string, object>)obj)[propName] = propValue

I don't know off the top of my head whether you can use the indexer syntax with a dynamic reference (i.e., without the cast), but you can certainly try it and find out.

Add properties of unknown name to expando object

Your question is a bit ambiguous, but:

Assuming data[0] contains the string "hello" and data[1] contains the string "world", I believe what you're trying to do is this (pseudocode):

eo.hello = world;

If so, you can simply cast the ExpandoObject to IDictionary<string, object>:

var dictionary = eo as IDictionary<string, object>;
dictionary.Add(data[0], data[1]);

Is it possible to use ExpandoObject to create run-time properties?

Just use the fact that it implements IDictionary<string, Object>:

IDictionary<string, Object> expando = new ExpandoObject();
expando[properties[0]] = 45;
expando[properties[1]] = "Good";
expando[properties[2]] = "Red";
expando[properties[3]] = 8;

dynamic d = expando;
// Now use the properties as normal

On the other hand, if you don't know the properties until execution time, what's actually going to consume them? It may still make sense to use ExpandoObject - but equally it may make sense to use Dictionary<string, object> to start with.

ExpandoObject add Property with extra-code

I think a better approach would be using DynamicObject which you can intercept the calls for
methods and properties.

This is a simple example, a more robust one would not use reflection to perform set/get operations on the property but rather using reflection.Emit or any compiled operation strategy.

public class Sample
{
public string SampleExtraString { get; set; }
}

public class Factory
{
public class ExtraPropertyObject<T> : DynamicObject
{
private readonly T instance = default(T);
private readonly Type instanceType = null;

public ExtraPropertyObject(T instance) {
this.instance = instance;
instanceType = instance.GetType();
}

public override bool TrySetMember(SetMemberBinder binder, object value) {
PropertyInfo prop = null;

if (binder.Name.Equals("SampleExtraString")) {
Console.WriteLine(value);
}

prop = instanceType.GetProperty(binder.Name);

if (prop != null) {
try {
prop.SetValue(instance, value);
return true;
}
catch (Exception ex) {

}
}

return false;
}

public override bool TryGetMember(GetMemberBinder binder, out object result) {
var prop = instanceType.GetProperty(binder.Name);

if (prop != null) {
try {
result = prop.GetValue(instance);
return true;
}
catch (Exception ex) {

}
}

result = null;
return false;
}
}

public static dynamic CreateInstance<TInstance>() where TInstance : class, new() {
return new ExtraPropertyObject<TInstance>(new TInstance());
}

public static dynamic CreateInstance<TInstance>(TInstance instance) {
return new ExtraPropertyObject<TInstance>(instance);
}
}

class Program
{
static void Main(string[] args) {
var instance = Factory.CreateInstance<Sample>();
instance.SampleExtraString = "value";
Console.WriteLine("Get Operation: {0}", instance.SampleExtraString);
}
}

Dynamically adding properties to a dynamic object?

dynamic d = new ExpandoObject();
((IDictionary<string,object>)d)["test"] = 1;
//now you have d.test = 1

Can an ExpandoObject have a strongly typed parent?

You can't of course let your ExpandoObject inherit from some other class, because inheritance is fixed and the base class is System.Object.

Also you can't inherit from ExpandoObject because it's sealed. So if you want to have both: type-safe, non-dynamic regulary declared properties and dynamically added ones, it's getting tricky, and you likely just can map an expando object to an existing object, so the expando is kind of a proxy for the non-dynamic instance.

You can write code that dynamically adds properties and their values to your ExpandoObject - you find in another classes instance.

The ExpandoObject is essentially an IDictionary<string, object> of property names and their values.

var expando = new ExpandoObject();
expando.SecondStringProperty = "2nd string";

IDictionary<string, object> expandoDic = expando;
var obj = new TypedProperties { ... };
foreach (var p in obj.GetType().GetProperties())
{
expandoDic.Add(p.Name, p.GetValue(obj));
}
//'expando' now contains all public props+values of obj plus the additional prop 'SecondStringProperty'

dynamic keyword with ExpandoObject to attach and remove properties

You can't cast from a dynamic type to a solid type like this as the type doesn't have anything to do with dynamic at that time other than looking like it as it has similar properties.

However, you could serialize the dynamic instance and then deserialize it to the solid type that you have. I'm not sure why you would want to do that though...

Dynamically adding dynamic properties at runtime

You could do something like this:

public static ExpandoObject Extend<T>(this T obj)
{
dynamic eo = new ExpandoObject();
var props = eo as IDictionary<string, object>;

PropertyInfo[] pinfo = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo p in pinfo)
props.Add(p.Name, p.GetValue(obj));

//If you need to add some property known at compile time
//you can do it like this:
eo.SomeExtension = "Some Value";

return eo;
}

This allows you to do this:

var p = new { Prop1 = "value 1", Prop2 = 123 };
dynamic obj = p.Extend();

Console.WriteLine(obj.Prop1); // Value 1
Console.WriteLine(obj.Prop2); // 123
Console.WriteLine(obj.SomeExtension); // Some Value


Related Topics



Leave a reply



Submit