3

Consider the following class:

public class TaxType
{
    public int Id {get;set;}
    public decimal TotalTaxCollected {get;set;}
    public string DetailXml {get;set;}
}

I got the following LINQ query somewhere in the code:

GetTaxTypesFromTheDataSource()
.Where(/*blah blah blah*/)
.GroupBy(t => new { t.Id })
.Select(g => new TaxType
{
    TotalTaxCollected = g.Sum(n => n.TotalTaxCollected),
    DetailXml = g.Aggregate(SumOfInnerElementsOfXml).DetailXml
})
.ToList();

Where SumOfInnerElementsOfXml is declared as follows:

private TaxType SumOfInnerElementsOfXml(TaxType t1, TaxType t2)
{
    //(a) Deserialize the t1.DetailXml & t2.DetailXml into 2 different arrays.
    //(b) Aggregate both arrays based on their IDs.
    //(c) Serialize the result into an xml string.
    //(d) Instantiate a new TaxType and set its DetailXml to the generated xml string.
    //return (d)
}

The above solution works fine, however I'd like to create my own aggregate function so that I can use it as follows:

GetTaxTypesFromTheDataSource()
.Where(/*blah blah blah*/)
.GroupBy(t => new { t.Id })
.Select(g => new TaxType
{
    TotalTaxCollected = g.Sum(n => n.TotalTaxCollected),
    DetailXml = g.MyCustomAggregateFunction(n => n.DetailXml)
})
.ToList();

How's that possible? I've tried several extension methods but unfortunately none of them worked.

0

1 Answer 1

4

Your initial solution seems pretty fine to me. However, if you don't like it...

To create a predefined function (not lambda), I'd recommend first to get rid of anonymous type in your query - change:

.GroupBy(t => new { t.Id })

to

.GroupBy(t => t.Id)

This is also generally better, as you get rid of one boxing/unboxing per TaxType and transform IGrouping<{anonymous},TaxType> into IGrouping<int,TaxType> (easier to understand the semantics if someone inspects the code later)

Then, you can declare the method as follows:

public static class Extensions {
    public static string MyCustomAggregateFunction(this IGrouping<int,TaxType> source, Func<TaxType,string> selector) {
        // blah-blah-blah
        //return something
    }
}

You can later make it generic if the need arises.

I'd also recommend getting rid of the dependency on IGrouping, as you later may need to apply that aggregation elsewhere:

TotalTaxCollected = g.Sum(n => n.TotalTaxCollected),
DetailXml = g.Select(n => n.DetailXml).AggregateTaxXML()

and

public static string AggregateTaxXML(this IEnumerable<string> source) {
    // blah-blah-blah
    //return something
}

Sources/further reading: MSDN

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.