简体   繁体   中英

c# Lambda referencing class object in Select method

I've written this code which works:

var uniqueCustomerIdList = services
    .GroupBy(x => x.CustomerId)
    .Select(cl => new Customer
    {
        CustomerId = cl.First().CustomerId,
        CustomerName = cl.First().CompanyName,
        PdfServices = services.Where(x => x.CustomerId == cl.First().CustomerId).ToList(),
        PdfServiceLines = services.Where(x => x.CustomerId == cl.First().CustomerId).ToList()
            .GroupBy(l => l.ServiceDescription)
            .Select(cy => new PdfServiceLine
            { 
                ServiceName = cy.First().ServiceDescription,
                Quantity = cy.Count(),
                UnitPrice = cy.First().PlanCharge,
                ServiceCharges = services.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.TotalBill),
                UsageCharges = usage.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.Charge),
                Total = cy.Sum(c => c.PlanCharge),
            }).ToList(),
        PdfUsages = usage.Where(x => x.CustomerId == cl.First().CustomerId).ToList()
    })
    .ToList();

I wanted to know if it's possible to reference values from the outer Select statement in the inner statement? As it looks rather clunky at the moment.

For instance in the outer Customer select I use PdfServices - can I use that in the inner select where I have ServiceCharges ?

ServiceCharges = PdfServices.Where(s => s.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.TotalBill)

instead of

ServiceCharges = services.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.TotalBill),

Thanks, Lee.

The results that you want to re-use are members of an anonymous object, not variables. As such, you cannot expect them to be available, like a variable would be, to the inner lambda. If you re-wrote your statement, you could store them in intermediate variables:

var uniqueCustomerIdList = services
    .GroupBy(x => x.CustomerId)
    .Select(cl =>
    {
        var pdfServices = services.Where(x => x.CustomerId == cl.First().CustomerId).ToList();
        return new Customer
        {
            CustomerId = cl.First().CustomerId,
            CustomerName = cl.First().CompanyName,
            PdfServices = pdfServices,
            PdfServiceLines = pdfServices
                .GroupBy(l => l.ServiceDescription)
                .Select(cy => new PdfServiceLine
                { 
                    ServiceName = cy.First().ServiceDescription,
                    Quantity = cy.Count(),
                    UnitPrice = cy.First().PlanCharge,
                    ServiceCharges = services.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.TotalBill),
                    UsageCharges = usage.Where(x => x.CustomerId == cl.First().CustomerId && x.ServiceDescription == cy.First().ServiceDescription).Sum(y => y.Charge),
                    Total = cy.Sum(c => c.PlanCharge),
                }).ToList(),
            PdfUsages = usage.Where(x => x.CustomerId == cl.First().CustomerId).ToList()
        };
    })
    .ToList();

Note that the lamda body now uses curly braces and a return statement. This is not convertible to an expression tree, and some ORM frameworks, like Entity Framework, will not be able to translate the lamda into SQL.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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