ExpandoObject 的简单测试失败。有人能解释一下为什么吗?

发布于 2024-10-16 12:21:37 字数 1773 浏览 0 评论 0原文

首先,错误消息

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”之前,仍然有效

?result

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()

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()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

野鹿林 2024-10-23 12:21:37

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

7.6.5.2 扩展方法调用

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

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

将: 替换

var first = root.Child.First();

为显式调用静态方法:

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

或者只是使用索引器:

var first = root.Child[0];

编辑:

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文