在 IEnumerable<dynamic> 上使用 LINQ 时出现编译器错误,但如果先将其转换为 IEnumerable<dynamic> 则不会
Compiler error when using LINQ on IEnumerable<dynamic> but not if you cast it to IEnumerable<dynamic> first
好的,所以我正在编写一些非常混乱的代码,因为我正在使用的库是 returning 动态类型层次结构。其中一些类型可以展开为动态类型列表,并使我能够在 LINQ 中使用这些动态对象层次结构,我写了一个小方法,基本上将一些动态对象转换为 IEnumerable。
我有这个方法 return 是一个 IEnumerable 但是当我尝试将它与 LINQ 一起使用时我得到错误 "Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type.",但是如果我转换方法 return 从 IEnumerable 到 IEnumerable 的值(在我看来是一个空操作),它编译并且工作正常。
任何人都可以向我解释这种行为吗?
void Main()
{
Foo(null).Select(value => value); // OK... I was expecting this to work.
dynamic unknown = new ExpandoObject();
Foo(unknown).Select(value => value); //COMPILER ERROR: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type... this was a bit more unexpected.
((IEnumerable<dynamic>)Foo(unknown)).Select(value => value); // OK... this was really unexpected.
}
IEnumerable<dynamic> Foo(dynamic param)
{
yield return "Tranformation logic from param to IEnumerable of param goes here.";
}
Foo(unknown)
的结果是dynamic
,不是IEnumerable<dynamic>
。这是因为对 Foo
的调用是动态解析的,因为 unknown
是 dynamic
.
要静态解析Foo
,您可以写object unknown = new ExpandoObject();
,或者将调用更改为Foo((object) unknown)
。
更糟糕的是 dynamic
不支持扩展方法。即使 T
是 dynamic
,也可以静态地找到 IEnumerable<T>
上的扩展方法,但是 C# 编译器不提供活动的 using
命名空间列表,所以如果你有纯 dynamic
,运行时间不知道去哪个类搜索扩展方法。即使 .Select(value => value)
可以被编译,也许通过将它变成 Func<dynamic, dynamic> projection = value => value;
然后 unknown.Select(projection)
(未经测试),它仍然会在 运行 时抛出异常。你需要明确地写 Enumerable.Select(unknown, projection)
才能让它工作。
好的,所以我正在编写一些非常混乱的代码,因为我正在使用的库是 returning 动态类型层次结构。其中一些类型可以展开为动态类型列表,并使我能够在 LINQ 中使用这些动态对象层次结构,我写了一个小方法,基本上将一些动态对象转换为 IEnumerable
我有这个方法 return 是一个 IEnumerable
任何人都可以向我解释这种行为吗?
void Main()
{
Foo(null).Select(value => value); // OK... I was expecting this to work.
dynamic unknown = new ExpandoObject();
Foo(unknown).Select(value => value); //COMPILER ERROR: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type... this was a bit more unexpected.
((IEnumerable<dynamic>)Foo(unknown)).Select(value => value); // OK... this was really unexpected.
}
IEnumerable<dynamic> Foo(dynamic param)
{
yield return "Tranformation logic from param to IEnumerable of param goes here.";
}
Foo(unknown)
的结果是dynamic
,不是IEnumerable<dynamic>
。这是因为对 Foo
的调用是动态解析的,因为 unknown
是 dynamic
.
要静态解析Foo
,您可以写object unknown = new ExpandoObject();
,或者将调用更改为Foo((object) unknown)
。
更糟糕的是 dynamic
不支持扩展方法。即使 T
是 dynamic
,也可以静态地找到 IEnumerable<T>
上的扩展方法,但是 C# 编译器不提供活动的 using
命名空间列表,所以如果你有纯 dynamic
,运行时间不知道去哪个类搜索扩展方法。即使 .Select(value => value)
可以被编译,也许通过将它变成 Func<dynamic, dynamic> projection = value => value;
然后 unknown.Select(projection)
(未经测试),它仍然会在 运行 时抛出异常。你需要明确地写 Enumerable.Select(unknown, projection)
才能让它工作。