我有一个很大的select
表达式可以在几个类中重用。对于DRY原则,我选择创建一个将Expression
返回给调用者代码的属性
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
};
}
}
现在我可以成功使用该属性
var query = dataContext.entity.Join(...).Where(x => ...).Select(Select);
但以下内容无法编译:
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>'
我可以理解LINQ语法要求select语句的主体是它返回的IQueryable
的内部类型,因此编译器被愚弄到返回表达式列表。使用Lambda语法,表达式是一个在线编译或由其他方法返回的参数(甚至是动态的!)。
我想问一下是否有办法绕过这个并避免在内联中定义大select
个表达式
答案 0 :(得分:2)
受保护的虚拟表达式&gt;选择
我将避免使用任何Linq映射方法(Select
,Where
,GroupBy
,OrderBy
,OrderByDescending
)的名称作为会员名称。它适用于这种情况,但是当它通过匹配那些定义而导致问题时,如果你不习惯不使用这些名称,除非你故意想要覆盖Linq,否则它会让人感到困惑。
相关说明。考虑一下:
from var item in source select item.Something
相当于:
source.Select(item => item.Something);
因此:
from SezioneJoin sj in (/*…*/) select Select;
相当于:
(/*…*/).Select(sj => Select);
也就是说,你不是'创建一个执行Select
中的表达式的查询,而是一个返回表达式的表达式。
您应该只使用表单.Select(Select)
或使用select sj => (Select)(sj)
,但第二个表单(如果我的括号正确,以阻止它与Queryable.Select
发生冲突,我没有每次都调用Select
属性,因此最多浪费,更糟糕的是不会成为查询提供者可以使用的东西,因此大多数linq提供者都会失败。总之,请使用.Select(Select)
表单(并更改名称)。
(另外注意,如果你要缓冲一个表达式,实际缓冲它;创建一个私有Expression<Func<SezioneJoin, QueryRow>>
一次并在属性的getter中返回它,而不是每次都创建它。)
答案 1 :(得分:1)
只需使用extension method代替最后一个LINQ select语句:
var query = from SezioneJoin sj ... select new SezioneJoin{...});
var projection = query.Select(Select);