C# 通过LINQ中的属性缓冲表达式(vs Lambda)

C# 通过LINQ中的属性缓冲表达式(vs Lambda),c#,linq,lambda,C#,Linq,Lambda,我有一个大的select表达式,可以在几个类中重用。对于原则,我选择创建一个属性,将表达式返回给调用方代码 protected virtual Expression<Func<SezioneJoin, QueryRow>> Select { get { return sj => new QueryRow { A01 = sj.A.A01,

我有一个大的
select
表达式,可以在几个类中重用。对于原则,我选择创建一个属性,将
表达式
返回给调用方代码

    protected virtual Expression<Func<SezioneJoin, QueryRow>> Select
    {
        get
        {
            return sj => new QueryRow
            {
                A01 = sj.A.A01,
                A01a = sj.A.A01a,
                A01b = sj.A.A01b,
                A02 = sj.A.A02,
                A03 = sj.A.A03,
                A11 = sj.A.A11,
                A12 = sj.A.A12,
                A12a = sj.A.A12a,
                A12b = sj.A.A12b,
                A12c = sj.A.A12c,
                A21 = sj.A.A21,
                A22 = sj.A.A22,
                ..............
                Lots of assignements
            };
        }
    }
但以下内容不会编译:

       from SezioneJoin sj in (
               from A a in ...
               join D d in ... on new { ... } equals new { ... }

               where
                    d.D13 == "086" &&
                    !String.IsNullOrEmpty(a.A32) && a.A32 != "086"
               orderby a.A21
               orderby a.prog
               select new SezioneJoin{...})

       select Select
错误是

Unable to cast 'System.Linq.IQueryable<System.Linq.Expressions.Expression<System.Func<DiagnosticoSite.Data.Query.SezioneJoin,DiagnosticoSite.Data.Query.QueryRow>>>' into 'System.Linq.IQueryable<DiagnosticoSite.Data.Query.QueryRow>'
无法将'System.Linq.IQueryable'强制转换为'System.Linq.IQueryable'
我可以理解LINQ语法要求select语句体是它返回的
IQueryable
的内部类型,因此编译器被愚弄,返回了一个表达式列表。使用Lambda语法,表达式是一个参数,它可以在线编译,也可以由其他方法返回(甚至是动态的!)

我想问一下,是否有任何方法可以绕过这一点,避免定义大型
select
内联表达式

仅用于替换最后一条LINQ select语句:

var query = from SezioneJoin sj ... select new SezioneJoin{...});
var projection = query.Select(Select);
受保护的虚拟表达式>选择

我会避免使用任何Linq映射方法的名称(
Select
Where
GroupBy
OrderBy
OrderByDescending
)作为成员名称。在这种情况下它是有效的,但是当它通过匹配这些名称的定义而导致问题时,如果您没有不使用这些名称的习惯,则可能会产生混淆,除非您有意希望覆盖Linq

在相关的注释上。考虑一下:

from var item in source select item.Something
相当于:

source.Select(item => item.Something);
(/*…*/).Select(sj => Select);
因此:

from SezioneJoin sj in (/*…*/) select Select;
相当于:

source.Select(item => item.Something);
(/*…*/).Select(sj => Select);
也就是说,您不是在创建执行
Select
中表达式的查询,而是返回表达式本身的查询

您应该只使用
.Select(Select)
或使用
Select sj=>(Select)(sj)
格式,但第二个格式会(如果我甚至正确地使用括号来阻止它与
Queryable发生冲突。Select
,我还没有对此进行测试)每次调用
Select
属性,这样做充其量是浪费,更糟糕的是查询提供程序无法使用,因此大多数linq提供程序都会失败。总之,使用
。选择(Select)
表单(并更改名称)


(另一方面,如果要缓冲一个表达式,请实际缓冲它;创建一个私有的
表达式
一次,并在属性的getter中返回它,而不是每次都创建它)。

重要注意事项,我建议对整个查询expect select语句使用LINQ。OP只提到他可以对整个查询使用扩展方法。无论如何,我现在仍然将LINQ括在括号中,然后发出Lambda