I've noticed that the new ExpandoObject
implements IDictionary<string,object>
which has the requisite IEnumerable<KeyValuePair<string, object>>
and Add(string, object)
methods and so it should be possible to use the collection initialiser syntax to add properties to the expando object in the same way as you add items to a dictionary.
Dictionary<string,object> dict = new Dictionary<string,object>()
{
{ "Hello", "World" }
};
dynamic obj = new ExpandoObject()
{
{ "foo", "hello" },
{ "bar", 42 },
{ "baz", new object() }
};
int value = obj.bar;
But there doesn't seem to be a way of doing that. Error:
'System.Dynamic.ExpandoObject' does not contain a definition for 'Add'
I assume this doesn't work because the interface is implemented explicitly. but is there any way of getting around that? This works fine,
IDictionary<string, object> exdict = new ExpandoObject() as IDictionary<string, object>();
exdict.Add("foo", "hello");
exdict.Add("bar", 42);
exdict.Add("baz", new object());
but the collection initializer syntax is much neater.
First of all, you are spot on. The
IDictionary<string,object>
has been implemented explicitly.You do not even need casting. This works:
Now the reason collection syntax does not work is because that is an implementation in theDictionary<T,T>
constructor and not part of the interface hence it will not work for expando.Wrong statement above. You are right, it uses add function:
Gets compiled to
UPDATE
The main reason is
Add
has been implemented asprotected
(with no modifier which becomesprotected
).Since
Add
is not visible onExpandoObject
, it cannot be called as above.Using the idea from @samedave, and adding reflection, I got this:
But it would be nicer to be able to just do it like:
Update:
Using Rick Strahl's Expando implementation you should be able to do something like this:
The opensource framework Dynamitey has an alternative syntax for building
ExpandoObject
instances inline.It also has a dictionary based dynamic prototype object
Dynamitey.DynamicObjects.Dictionary
such thatworks too.
The language specification (7.5.10.3 on Collection Initializers) is a bit vague on this point as far as I can tell. It says
Unfortunately the text doesn't go into details about what an applicable Add method is, but it seems that explicitly implemented interface methods don't fit the bill as they are essentially considered private (see 13.4.1):
I've had the need for a simple ExpandoObject initializer several times before and typically use the following two extension methods to accomplish something like initializer syntax:
Then you can write the following:
In general I've found that having an extension method to build
KeyValuePair<string, object>
instances from a string key comes in handy. You can obviously change the name to something likeIs
so that you can write"Key".Is("Value")
if you need the syntax to be even more terse.It's a shame that adding dynamic properties (whose name is known only at run-time) to
ExpandoObject
is not as easy as it should have been. All the casting to dictionary is plain ugly. Never mind you could always write a customDynamicObject
that implementsAdd
which helps you with neat object initializer like syntax.A rough example:
And you could call like you wanted:
The caveat with this approach is that you cannot add
Add
"method" with the same signature as Dictionary.Add to your expando object since it is already a valid member of theExpando
class (which was required for the collection initializer syntax). The code throws an exception if you doIf property names needn't be truly dynamic then another alternative is to have a
ToDynamic
extension method so that you can initialize in-line.So you can call:
There are a hundred ways you can design an API for this, another one such (mentioned in orad's answer) is:
Will be trivial to implement.
Side note: there is always anonymous types if you know the property names statically and you dont want to add further after initialization.