使用LINQ操作IEnumerable<dynamic>时出现编译错误,但如果先将其转换为IEnumerable<dynamic>则不会出错。

4

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

我有一个返回IEnumerable<dynamic>的方法,但是当我尝试在LINQ中使用它时,会出现错误“无法在不首先将其强制转换为委托或表达式树类型的情况下使用Lambda表达式作为动态分派操作的参数。”,但是如果我将方法的返回值从IEnumerable<dynamic>转换为IEnumerable<dynamic>(在我看来是一个无操作),它就可以编译并正常工作。

有人能解释一下这种行为吗?

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

http://www.mikesdotnetting.com/article/198/cannot-use-a-lambda-expression-as-an-argument-to-a-dynamically-dispatched-operati - Nacho
1个回答

4
Foo(unknown)的结果是dynamic,而不是IEnumerable<dynamic>。这是因为对Foo的调用是动态解析的,因为unknowndynamic
要静态解析Foo,您可以编写object unknown = new ExpandoObject();,或将调用更改为Foo((object) unknown)
更糟糕的是,扩展方法在dynamic上不受支持。即使TdynamicIEnumerable<T>上的扩展方法也可以被静态地找到,但是C#编译器不提供活动using命名空间列表,因此如果您只有纯dynamic,运行时不知道要搜索哪些类的扩展方法。即使.Select(value => value)可以被编译,也许通过将其转换为Func<dynamic, dynamic> projection = value => value;,然后unknown.Select(projection)(未经测试)可能会抛出异常。您需要明确编写Enumerable.Select(unknown, projection)才能使其正常工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接