ExpandoObject 的简单测试失败。有人能解释一下为什么吗?
首先,错误消息
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
dynamic
目前不适用于扩展方法;当 LINQ to ObjectsFirst
方法“作为”扩展方法调用时,编译器将无法在运行时“动态”绑定到该方法。从语言规范来看:要了解原因,您可能需要阅读 C#4 中的动态关键字是否支持扩展方法?
将: 替换
为显式调用静态方法:
或者只是使用索引器:
编辑:
变量
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 ObjectsFirst
method at run-time when it is invoked "as" an extension-method. From the language specification:To understand why, you might want to read Will the dynamic keyword in C#4 support extension methods?
Replace:
with an explicit call to the static method:
or simply be using the indexer:
EDIT:
The variable
result
is implicitly typed toIEnumerable<dynamic>
; this is its compile-time (static) type. In this case, when you doresult.First()
, the compiler has no problems binding to theEnumerable.First
method at compile-time. If you changed the compile-time type ofresult
todynamic
, the error would recur.