如果调用 ToList 或 ToArray,为什么 C# 编译器允许在表达式树中使用动态操作

Why does C# compiler allow use of a dynamic operation in expression tree if ToList or ToArray is called

请注意:我知道有很多与此处讨论的主要错误消息相关,但我 找不到任何 post 讨论我的问题。

因此,在将其标记为重复之前,请阅读到最后。

一如既往,如果您能指出一个讨论我感到困惑的问题的问题,我很乐意记下这个问题。


我有一个方法 returns 如下所示的 IQueryable

public IQueryable<dynamic> GetData(DateTime Start, DateTime End, Nullable<int> EmployeeId = null)
{
    var query = from T1 in Context.Table1
                join T2 in Context.Table2
                on T1.Col1 equals T2.Col1
                join T3 in Context.Table3
                on T2.Col1 equals T3.Col1
                where T1.Col1 == EmployeeId
                        && T1.Col2 >= Start
                        && T1.Col2 <= End
                select new
                {
                    Value1 = T1.Col1,
                    Value2 = T2.Col5,
                    Value3 = T3.Col7

                };

    return query;
}

请注意,由于 table 的敏感性,我不得不删除 table 和列名。

问题:

我想从另一个 class 中得到 Value3 的总和。

private float getTargetScore()
{
    return GetData().Sum(rec => Convert.ToSingle(rec.Value3));
}

这给了我以下编译器错误。

An expression tree may not contain a dynamic operation

令人困惑的部分:

如果在调用 Sum() 之前添加 .ToList() 或 .ToArray(),我不会收到此编译器错误

private float getTargetScore()
{
    return GetData().ToArray().Sum(rec => Convert.ToSingle(rec.Value3));
}

我知道 .ToList() 或 .ToArray() 实现了查询(在这种情况下从数据库中获取数据)并导致 IEnumerable<> 而不是 IQueryable<> 但是为什么C# 编译器允许我在此处的表达式中使用动态操作?

注意:C#版本为4.0 (.Net 4.0)

在第一种情况下,您调用的是 IQueryable.Sum

public static int Sum<TSource>(this IQueryable<TSource> source,
                                    Expression<Func<TSource, int>> selector)

在第二种情况下,您调用的是 IEnumerable.Sum

 public static int Sum<TSource>(this IEnumerable<TSource> source,
                                     Func<TSource, int> selector)

因此,在第一种情况下,编译器会尝试从 lambda 表达式创建一个 表达式树 ,但由于您使用的是动态的,因此无法执行此操作。