如何动态构建Func <t,u =“”>?</t,>

时间:2014-04-21 12:48:58

标签: c# linq func

我有以下代码,我想将其放入一个函数中,因此我不需要为if-block的每个案例多次复制/粘贴它:

        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

用于排序&#34;卡片的属性的类型T&#34; by始终是Enum。 到目前为止,我有以下方法可以调用:

    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>()的最后一个参数的问题,这是用于过滤的谓词,因为我需要为外循环的每次运行使用不同的谓词。我无法将其作为固定参数传递,因为我显然无法引用&#34;值&#34;在外部的foreach循环中。所以我认为我必须在AddSections函数内动态构建它。如果是这种情况,我该怎么做,或者我完全走错了轨道?

2 个答案:

答案 0 :(得分:3)

这里的诀窍是用Func<CardViewModel, bool> predicate替换Func<T, Func<CardViewModel, bool>> predicateFactory

我认为这就是诀窍:

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

答案 1 :(得分:0)

你可以这样做:

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构建实际的谓词。