c#lambda表达式 - 将委托结果添加到通用列表

时间:2009-04-23 18:23:34

标签: c# .net .net-3.5 lambda

问题:我刚刚使用c#lambda表达式编写了我的第一个代码。它有效,但我不确定这是否是最好的方法。关于更好地进行lambda表达式的任何建议?在表达式中有很多行代码似乎很奇怪,就像我在下面所做的那样。

背景:我有一个通用的代表列表。每个委托函数返回一个枚举值,指示函数中发生的事情。在评估委托时,我需要将枚举添加到List中,如果它不是特定的枚举值。

免责声明:这里的代码非常通用,真正的代码实际上在委托中确定了返回值!


class Class1
{
    public enum WhatHappened
    {
        ThingA,
        ThingB,
        Nothing
    }

    private delegate WhatHappened del();

    public static List<WhatHappened> DoStuff()
    {
        List<del> CheckValues = new List<del>();

        List<WhatHappened> returnValue = new List<WhatHappened> { };

        CheckValues.Add(delegate { return method1(); });
        CheckValues.Add(delegate { return method2(); });

        CheckValues.ForEach(x =>
        {
            WhatHappened wh = x();
            if (wh != WhatHappened.Nothing)
                returnValue.Add(wh);
        });

        return returnValue;

    }

    private static WhatHappened method1()
    {
        return WhatHappened.Nothing;
    }

    private static WhatHappened method2()
    {
        return WhatHappened.ThingA;
    }

}

注意:我最初有lambda喜欢添加所有项目(见下文),然后删除我不想要的(WhatHappened.Nothing)。

CheckValues.ForEach(x => returnValue.Add(x()));

7 个答案:

答案 0 :(得分:9)

好的,一些建议:

  • 请勿致电您的代表del。在这种情况下,我使用Func<WhatHappened> - 但是如果您想要声明自己的委托类型,请为其指定一个更具描述性的名称,并遵守.NET命名约定。
  • 您可以使用以下命令,而不是使用匿名方法添加到CheckValues

    CheckValues.Add(method1);
    CheckValues.Add(method2);
    

    编译器会将方法组转换为委托。

  • 我建议不要使用Pascal大小写来开始本地变量名。

  • returnValues的集合初始化程序并没有真正为您做任何事情 - 只需正常调用List<T>构造函数,或者使用下面不需要本地变量的代码。
  • 如果你的列表真的只有两个代表,我只是单独调用它们。它简单得多。
  • 否则你确实可以像Jared所说的那样使用LINQ,但我的做法略有不同:

    return CheckValues.Select(x => x())
                      .Where(wh => wh != WhatHappened.Nothing)
                      .ToList();
    

编辑:正如所建议的,这是完整的例子。虽然它与Denis不太一样......我做了一些改变:)

public static List<WhatHappened> DoStuff()
{
    var functions = new List<Func<WhatHappened>> { Method1, Method2 };

    return functions.Select(function => function())
                    .Where(result => result != WhatHappened.Nothing)
                    .ToList();
}

(我假设method1method2已经重命名以符合命名惯例。当然在现实生活中我肯定他们还有更多有用的名字......)

答案 1 :(得分:3)

你可以通过链接Select(map)和Where(filter)而不是多个FOR循环和IF语句来一直运行lambda

// get results from the list of functions
var results = CheckValues.Select(x => x());

// filter out only the relevant ones.
var returnValues = results.Where(x => x != WhatHappened.Nothing);

基本上,在使用lambdas时,您应该考虑更多 declaratively 而不是 imperatively 。它可以帮助你编写更优雅的代码。

答案 2 :(得分:3)

我只想使用Linq,但那只是我:

public static List<WhatHappened> DoStuff()
{
    List<del> CheckValues = new List<del>();

    List<WhatHappened> returnValue = new List<WhatHappened>();

    CheckValues.Add(method1);
    CheckValues.Add(method2);

    return CheckValues
               .Select(dlg => dlg())
               .Where( res => res != WhatHappened.Nothing)
               .ToList();
}

请注意,如果需要,您也可以使用Func而不是声明Delegate类型,但在这种情况下则不那么简洁。 另外,我会返回一个IEnumerable<WhatHappened>而不是一个List,但这完全取决于上下文。

答案 3 :(得分:2)

编写以下内容而不是使用delegate关键字更加惯用。但它并没有改变底层功能。

CheckValues.Add( () => method1() );

另外,我发现将ForEach重写为以下

更具可读性
CheckValues = CheckValues.
  Select(x => x()).
  Where(wh => wh != WhatHappened.Nothing ). 
  ToList();

答案 4 :(得分:1)

在我看来,基于这个例子,它看起来很好。你可以通过替换来重构:

CheckValues.Add(delegate { return method1(); });
CheckValues.Add(delegate { return method2(); });

使用:

CheckValues.Add(() => WhatHappened.Nothing);
CheckValues.Add(() => WhatHappened.ThingA);

答案 5 :(得分:1)

这是一个无LINQ的解决方案:

return CheckValues
    .ConvertAll<WhatHappened>(x => x())
    .FindAll(y => y != WhatHappened.Nothing);

<强>警告

这不是最高效的解决方案,因为它会迭代两次。

答案 6 :(得分:0)

我无法理解代码的目的..但是这里有。
使用委托链接 更新:并从Jon n Jared的帖子中获得了一些可数的好处

private delegate WhatHappened WhatHappenedDelegate();

public static List<WhatHappened> DoStuff()
{
    WhatHappenedDelegate delegateChain = null;
    delegateChain += method1;
    delegateChain += method2;

    return delegateChain.GetInvocationList() 
            .Select(x => (WhatHappened) x.DynamicInvoke())
            .Where( wh => (wh != WhatHappened.Nothing))
            .ToList<WhatHappened>();
}