Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I index into an ExpandoObject?

Something caught me by surprise when looking into C# dynamics today (I've never used them much, but lately I've been experimenting with the Nancy web framework). I found that I couldn't do this:

dynamic expando = new ExpandoObject();  expando.name = "John";  Console.WriteLine(expando["name"]); 

The last line throws an exception:

Cannot apply indexing with [] to an expression of type 'System.Dynamic.ExpandoObject'

I understand the error message, but I don't understand why this is happening. I have looked at the documentation for ExpandoObject and it explicitly implements IDictionary<,> and thus has a this.[index] method (MSDN). Why can't I call it?

Of course, there's nothing to stop me from downcasting the ExpandoObject to a dictionary manually and then indexing into it, but that kind of defies the point; it also doesn't explain how the Expando was able to hide the method of one of its interfaces.

What's going on here?

like image 348
Richiban Avatar asked Nov 06 '14 11:11

Richiban


People also ask

How do I know if I have expandoObject property?

You can use this to see if a member is defined: var expandoObject = ...; if(((IDictionary<String, object>)expandoObject). ContainsKey("SomeMember")) { // expandoObject. SomeMember exists. }

What is expandoObject in C#?

The ExpandoObject class enables you to add and delete members of its instances at run time and also to set and get values of these members. This class supports dynamic binding, which enables you to use standard syntax like sampleObject.


2 Answers

how the Expando was able to hide the method of one of its interfaces.

Because as you correctly found out in the documentation, the indexer is an explicit interface implementation. From Explicit Interface Implementation Tutorial:

A class that implements an interface can explicitly implement a member of that interface. When a member is explicitly implemented, it cannot be accessed through a class instance, but only through an instance of the interface.

This means you'll have to cast the reference to the interface to access it:

((IDictionary<String, Object>)expando)["name"] 
like image 92
CodeCaster Avatar answered Oct 08 '22 04:10

CodeCaster


Use this factory class to create ExpandoObjects! Then use HasProperty("prop name") or GetValue("prop name")

void Main() {     dynamic _obj = ExpandoObjectFactory.Create();     if (_obj.HasProperty("Foo") == false)     {         _obj.Foo = "Foo";     }     Console.WriteLine(_obj); // Foo;     object bar = _obj.GetValue("Bar");     Console.WriteLine(bar); // null }  public static class ExpandoObjectFactory {     public static ExpandoObject Create()     {         dynamic expandoObject = new ExpandoObject();         expandoObject.HasProperty = new Func<string, bool>((string name) => ((IDictionary<string, object>)expandoObject).ContainsKey(name));         expandoObject.GetValue = new Func<string, object>(delegate (string name)         {             ((IDictionary<string, object>)expandoObject).TryGetValue(name, out object value);             return value;         });         return expandoObject;     } } 
like image 45
Zekaee Esmaeel Avatar answered Oct 08 '22 04:10

Zekaee Esmaeel