繁体   English   中英

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

[英]Buffering an expression via property in LINQ (vs Lambda)

我有一个大的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表达式

protected virtual Expression>选择

我会避免使用任何Linq映射方法的名称( SelectWhereGroupByOrderByOrderByDescending )作为成员名称。 它适用于这种情况,但是当它通过匹配那些定义而导致问题时,如果你不习惯不使用这些名称,除非你故意想要覆盖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中返回它,而不是每次都创建它)。

只需使用扩展方法代替最后一个LINQ select语句:

var query = from SezioneJoin sj ... select new SezioneJoin{...});
var projection = query.Select(Select);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM