2013-12-04 2 views
2

Рассмотрим следующий класс:Создание пользовательского агрегатной функции в C# с помощью LINQ

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

Я получил следующий LINQ запрос где-то в коде:

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(); 

Где объявлен SumOfInnerElementsOfXml следующим образом:

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) 
} 

Вышеупомянутое решение работает отлично, однако я хотел бы создать свою собственную совокупную функциональность n, так что я могу использовать его следующим образом:

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(); 

Как это возможно? Я пробовал несколько методов расширения, но, к сожалению, никто из них не работал.

+0

Similiar: http://stackoverflow.com/questions/20372119/creating-a-custom-aggregate-function-in-c-sharp-using-linq –

ответ

3

Ваше первоначальное решение кажется мне очень хорошим. Однако, если вам не нравится это ...

Для создания предопределенных функций (а не лямбда), я рекомендовал бы первым, чтобы избавиться от анонимного типа в запросе - изменение:

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

в

.GroupBy(t => t.Id) 

Это также обычно лучше, так как вы избавляетесь от одного бокса/распаковки в TaxType и превратить IGrouping<{anonymous},TaxType> в IGrouping<int,TaxType> (проще понять семантику, если кто-то проверяет код позже)

Затем вы можете объявить метод следующим образом:

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

Вы можете позже сделать его общим, если возникнет необходимость.

Я также рекомендую, чтобы избавиться от зависимости от IGrouping, как вы позже, возможно, потребуется применить, что агрегация в другом месте:

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

и

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

Источники/дополнительная литература: MSDN

Смежные вопросы