The trick here is to replace Func<CardViewModel, bool> predicate
with Func<T, Func<CardViewModel, bool>> predicateFactory
.
I think this does the trick:
private void AddSections<T>(
IEnumerable<CardViewModel> cards,
StringBuilder builder,
Func<CardViewModel, T> order,
Func<T, Func<CardViewModel, bool>> predicateFactory)
{
cards = cards.OrderBy(order);
foreach (T value in Enum.GetValues(typeof(T)))
{
if (!cards.Any(predicateFactory(value)))
continue;
builder.Append(value.ToString() + ": ");
builder.Append(cards
.Where(predicateFactory(value))
.Sum(f => f.AmountInDeck));
builder.Append(Environment.NewLine);
foreach (CardViewModel card in cards.Where(predicateFactory(value)))
{
builder.Append(card.AmountInDeck.ToString()
+ "\t"
+ card.Name.Name
+ Environment.NewLine);
}
builder.Append(Environment.NewLine);
}
}
Your call to AddSections
would look like this:
this.AddSections<CardTypes>(cards, builder,
m => m.CardType,
v => m => m.CardType == v);
Alternatively, you might be able to simply shortcut the need to pass a predicate (or predicate factory) at all. Since it appears you are just dealing with enums you could do this:
private void AddSections<T>(
IEnumerable<CardViewModel> cards,
StringBuilder builder,
Func<CardViewModel, T> order)
{
cards = cards.OrderBy(order);
foreach (T value in Enum.GetValues(typeof(T)))
{
if (!cards.Any(c => order(c) == value))
continue;
builder.Append(value.ToString() + ": ");
builder.Append(cards
.Where(c => order(c) == value)
.Sum(f => f.AmountInDeck));
builder.Append(Environment.NewLine);
foreach (CardViewModel card in cards.Where(c => order(c) == value))
{
builder.Append(card.AmountInDeck.ToString()
+ "\t"
+ card.Name.Name
+ Environment.NewLine);
}
builder.Append(Environment.NewLine);
}
}
And then your call becomes this:
this.AddSections<CardTypes>(cards, builder, m => m.CardType);