在IEnumerable <dynamic>上使用LINQ时出现编译器错误,但如果将其强制转换为IEnumerable <dynamic>则不会出现

时间:2015-05-21 21:16:58

标签: c# linq dynamic ienumerable

好的,所以我正在编写一些非常混乱的代码,因为我正在使用的库是返回动态类型层次结构。其中一些类型可以展开到动态类型列表,并使我能够在LINQ中使用这些动态对象层次结构我写了一个基本上将一些动态对象转换为IEnumerable&lt; dynamic&gt;的方法。

我有这个方法返回IEnumerable&lt; dynamic&gt;但是当我尝试将它与LINQ一起使用时,我得到错误“不能将lambda表达式用作动态调度操作的参数,而不先将其转换为委托或表达式树类型。”但是,如果我转换方法返回值IEnumerable的&LT;动态&GT;到IEnumerable&lt; dynamic&gt; (在我看来是一个无操作),它编译并且工作正常。

有人可以向我解释这种行为吗?

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.";
}

1 个答案:

答案 0 :(得分:4)

Foo(unknown)的结果是dynamic,而不是IEnumerable<dynamic>。这是因为Foo的调用是动态解决的,因为unknowndynamic

要静态解决Foo,您可以撰写object unknown = new ExpandoObject();,或将来电更改为Foo((object) unknown)

更糟糕的是dynamic不支持扩展方法。即使IEnumerable<T>T,也可以静态找到dynamic上的扩展方法,但C#编译器不提供活动using命名空间的列表,因此如果您有明文{ {1}},运行时不知道要搜索扩展方法的类。即使dynamic可以编译,也许可以将其转换为.Select(value => value)然后Func<dynamic, dynamic> projection = value => value;(未经测试),它仍会在运行时抛出异常。您需要明确地编写unknown.Select(projection)以使其正常工作。