对ExpandoObject进行简单测试失败.谁能解释为什么?

epi*_*tka 5 c# dynamic

首先是错误信息

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:'System.Collections.Generic.List'在System.Dynamic.UpdateDelegates.UpdateAndExecute1(CallSite站点,T0)的CallSite.Target(Closure,CallSite,Object)中不包含'First'的定义. arg0)在ToPropertyDictionaryTests.cs中的ClaySharp.Tests.ToPropertyDictionaryTests.TestExpando():第91行

测试:

[测试]

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;
}
Run Code Online (Sandbox Code Playgroud)

有趣的是,如果从图片中删除"root",并且对"结果"执行测试而不是正常工作.

现在对于非常奇怪的部分.在返回"toReturn"之前调试是设定点.看看这个,它的确有效

?toReturn.GetType().全名

"System.Collections.Generic.List`1 [[System.Object,mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]]"

?回来

Count = 2 [0]:{System.Dynamic.ExpandoObject} [1]:{System.Dynamic.ExpandoObject}

?toReturn.First()

{} System.Dynamic.ExpandoObject

就在它被分配到"root"之前,仍然有效

?结果

Count = 2 [0]:{System.Dynamic.ExpandoObject} [1]:{System.Dynamic.ExpandoObject}

?result.First()

{} System.Dynamic.ExpandoObject

但在将其分配给root后,此操作将失败

?root.Child

{System.Collections.Generic.List} [0]:{System.Dynamic.ExpandoObject} [1]:{System.Dynamic.ExpandoObject}

?root.Child.First()

Ani*_*Ani 6

dynamic目前不适用于扩展方法; First当"作为"扩展方法调用时,编译器将无法在运行时"动态"绑定到LINQ to Objects 方法.从语言规范:

7.6.5.2扩展方法调用

...如果调用的正常处理找不到适用的方法,则尝试将构造作为扩展方法调用进行处理.如果expr或任何args具有编译时类型dynamic,则扩展方法将不适用.

要了解原因,您可能希望阅读C#4中的动态关键字是否支持扩展方法?

更换:

var first = root.Child.First();
Run Code Online (Sandbox Code Playgroud)

显式调用静态方法:

var first = Enumerable.First(root.Child);
Run Code Online (Sandbox Code Playgroud)

或者只是使用索引器:

var first = root.Child[0];
Run Code Online (Sandbox Code Playgroud)

编辑:

有趣的是,如果从图片中删除"root",并且对"结果"执行测试而不是正常工作.

该变量result隐式输入IEnumerable<dynamic>; 这是它的编译时(静态)类型.在这种情况下,当您这样做时result.First(),编译器Enumerable.First编译时绑定到该方法没有问题.如果您将编译时类型更改resultdynamic,则错误将重复出现.