如何构建Func<;T、 U>;动态地
本文关键字:gt 动态 何构建 lt 构建 Func | 更新日期: 2023-09-27 17:59:15
我有以下代码,我想把它们放进一个函数中,这样我就不必为if块的每种情况复制/粘贴多次:
if (sort == ExportSortOrder.CardType)
{
cards = cards.OrderBy(f => f.CardType);
foreach (CardTypes type in Enum.GetValues(typeof(CardTypes)))
{
if (!cards.Any(f => f.CardType == type))
continue;
builder.Append(type.ToString() + ": ");
builder.Append(cards.Where(f => f.CardType== type).Sum(f => f.AmountInDeck));
builder.Append(Environment.NewLine);
foreach (CardViewModel card in cards.Where(f => f.CardType == type))
{
builder.Append(card.AmountInDeck.ToString() + "'t" + card.Name.Name + Environment.NewLine);
}
builder.Append(Environment.NewLine);
}
}
else if ( //same code block as above, for a different property of CardViewModel
要对"卡片"进行排序的属性的类型T始终是枚举。到目前为止,我有以下方法可以调用:
private void AddSections<T>(IEnumerable<CardViewModel> cards, StringBuilder builder, Func<CardViewModel, T> order, Func<CardViewModel, bool> predicate)
{
cards = cards.OrderBy(order);
foreach (T value in Enum.GetValues(typeof(T)))
{
if (!cards.Any(predicate))
continue;
builder.Append(value.ToString() + ": ");
builder.Append(cards.Where(predicate).Sum(f => f.AmountInDeck));
builder.Append(Environment.NewLine);
foreach (CardViewModel card in cards.Where(predicate))
{
builder.Append(card.AmountInDeck.ToString() + "'t" + card.Name.Name + Environment.NewLine);
}
builder.Append(Environment.NewLine);
}
}
然而,现在我有一个问题,那就是如何构建AddSections<T>()
的最后一个参数,即要过滤的谓词,因为每次运行外循环都需要一个不同的谓词。我不能将其作为固定参数传递,因为我显然不能在foreach外部循环中引用"value"。所以我认为我必须在AddSections函数中动态构建它。如果是这样的话,我该怎么做,还是我完全走错了轨道?
这里的诀窍是用Func<T, Func<CardViewModel, bool>> predicateFactory
替换Func<CardViewModel, bool> predicate
。
我认为这很管用:
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);
}
}
您对AddSections
的呼叫如下所示:
this.AddSections<CardTypes>(cards, builder,
m => m.CardType,
v => m => m.CardType == v);
或者,您可以简单地缩短传递谓词(或谓词工厂)的需要。既然看起来你只是在处理枚举,你可以这样做:
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);
}
}
然后你的电话变成这样:
this.AddSections<CardTypes>(cards, builder, m => m.CardType);
你可以这样做:
private void AddSections<T>(
IEnumerable<CardViewModel> cards,
StringBuilder builder,
Func<CardViewModel, T> order,
Func<CardViewModel, T, bool> prepredicate)
{
cards = cards.OrderBy(order);
foreach (T value in Enum.GetValues(typeof(T)))
{
Func<CardViewModel, bool> predicate = f => prepredicate(f,value);
...
AddSections<CardTypes>(cards, builder, order, (f,t) => f.CardType == t);
我们给函数AddSection
一个可以用来建立谓词的函数。在循环中,我们可以使用lambda来构建实际的谓词。