OK,所以我正在编写一些非常混乱的代码,因为我正在使用的库正在返回动态类型层次结构。其中一些类型可以展开为动态类型列表,为了使我能够在LINQ中使用这些动态对象层次结构,我编写了一个小方法,基本上将一些动态对象转换为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)
以使其工作