如何构建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、 U>;动态地

这里的诀窍是用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来构建实际的谓词。