【问题标题】:Failing simple test for ExpandoObject. Can anybody explain why?ExpandoObject 的简单测试失败。谁能解释为什么?
【发布时间】:2011-02-06 13:55:05
【问题描述】:

首先是错误信息

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:“System.Collections.Generic.List”不包含“First”的定义 在 CallSite.Target(闭包,CallSite,对象) 在 System.Dynamic.UpdateDelegates.UpdateAndExecute1(CallSite 站点,T0 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;
}

有趣的是,如果从图片中删除“root”,并针对“结果”执行测试,则它可以正常工作。

现在是非常奇怪的部分。调试是在“toReturn”返回之前的设置点。看看这个,它有效

?toReturn.GetType().FullName

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

?返回

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

?toReturn.First()

{System.Dynamic.ExpandoObject}

在它被分配给“root”之前,仍然有效

?结果

计数 = 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()

【问题讨论】:

    标签: c# dynamic


    【解决方案1】:

    dynamic 目前不适用于扩展方法;当它被“作为”扩展方法调用时,编译器将无法在运行时“动态地”绑定到 LINQ to Objects First 方法。来自语言规范:

    7.6.5.2 扩展方法调用

    ...如果正常处理 调用发现不适用 方法,尝试处理 作为扩展方法的构造 调用。如果 expr 或任何参数 具有编译时类型动态, 扩展方法将不适用。

    要了解原因,您可能需要阅读Will the dynamic keyword in C#4 support extension methods?

    替换:

    var first = root.Child.First();
    

    显式调用静态方法:

    var first = Enumerable.First(root.Child);
    

    或者只是使用索引器:

    var first = root.Child[0];
    

    编辑:

    有趣的是,如果“root”是 从图片中删除,测试是 对“结果”的表现比它 工作正常。

    变量result被隐式类型化为IEnumerable&lt;dynamic&gt;;这是它的编译时(静态)类型。在这种情况下,当您执行result.First() 时,编译器在编译时 绑定到Enumerable.First 方法没有问题。如果将result的编译时类型更改为dynamic,则会再次出现错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-16
      • 1970-01-01
      • 1970-01-01
      • 2018-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多