Creating a custom aggregate function in C# using LINQ
c#, c#-4.0, linq
Solution
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
Problem
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.