First the error message
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException : 'System.Collections.Generic.List' does not contain a definition for 'First' at CallSite.Target(Closure, CallSite, Object) at System.Dynamic.UpdateDelegates.UpdateAndExecute1(CallSite site, T0 arg0) at ClaySharp.Tests.ToPropertyDictionaryTests.TestExpando() in ToPropertyDictionaryTests.cs: line 91
Test:
[Test]
public void TestExpando()
{
dynamic root = new ExpandoObject();
root.Name = "Name";
var result = GetExpandos();
root.Child = result;
var first = root.Child.First();
Assert.That(first.Name, Is.EqualTo("Obj1"));
}
private IEnumerable<dynamic> GetExpandos()
{
var toReturn = new List<dynamic>();
dynamic obj1 = new ExpandoObject();
toReturn.Add(obj1);
obj1.Name = "Obj1";
dynamic obj2 = new ExpandoObject();
toReturn.Add(obj2);
obj2.Name = "Obj2";
return toReturn;
}
Interesting part is that if "root" is removed from the picture, and test is performed against the "result" than it works fine.
And now for the very wierd part. Debug is set point just before "toReturn" is returned. Take a look at this, it works
?toReturn.GetType().FullName
"System.Collections.Generic.List`1[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"
?toReturn
Count = 2 [0]: {System.Dynamic.ExpandoObject} [1]: {System.Dynamic.ExpandoObject}
?toReturn.First()
{System.Dynamic.ExpandoObject}
And just before it is assigned to "root", still works
?result
Count = 2 [0]: {System.Dynamic.ExpandoObject} [1]: {System.Dynamic.ExpandoObject}
?result.First()
{System.Dynamic.ExpandoObject}
but after it is assigned to root, this fails
?root.Child
{System.Collections.Generic.List} [0]: {System.Dynamic.ExpandoObject} [1]: {System.Dynamic.ExpandoObject}
?root.Child.First()
dynamic
currently doesn't work well with extension methods; the compiler won't be able to "dynamically" bind to the LINQ to Objects First
method at run-time when it is invoked "as" an extension-method. From the language specification:
7.6.5.2 Extension method invocations
...if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation. If expr or any of the args has compile-time type dynamic, extension methods will not apply.
To understand why, you might want to read Will the dynamic keyword in C#4 support extension methods?
Replace:
var first = root.Child.First();
with an explicit call to the static method:
var first = Enumerable.First(root.Child);
or simply be using the indexer:
var first = root.Child[0];
EDIT:
Interesting part is that if "root" is removed from the picture, and test is performed against the "result" than it works fine.
The variable result
is implicitly typed to IEnumerable<dynamic>
; this is its compile-time (static) type. In this case, when you do result.First()
, the compiler has no problems binding to the Enumerable.First
method at compile-time. If you changed the compile-time type of result
to dynamic
, the error would recur.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With