2009-04-23 76 views
1

问题:我刚刚写了第一个使用c#lambda表达式的代码。它有效,但我不确定这是否是最好的方式。任何建议更好的方式来做lambda表达式?在表达式中有许多代码行似乎很奇怪,就像我在下面做的那样。c#lambda表达式 - 将代表结果添加到通用列表

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

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


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

} 

注:我本来喜欢将所有的项目(见下文),然后除去我不想让那些(WhatHappened.Nothing)拉姆达。

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

回答

9

好吧,几点建议:

  • 不要叫你的委托del。在这种情况下,我会使用Func<WhatHappened> - 但如果您想声明自己的委托类型,给它一个更具描述性的名称,并服从.NET命名约定。
  • 而不是使用匿名方法添加到CheckValues的,你可以用:

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

    编译器将方法组转换为代表。

  • 我建议不使用Pascal大小写的局部变量名开始。

  • returnValues您的集合初始是不是真的为你做任何事情 - 只是调用List<T>构造正常,或者用我下面的代码,它不需要一个局部变量开始。
  • 如果您的列表真的只中有两名代表,我只是分别给他们打电话。这简单得多。
  • 否则,你的确可以使用LINQ作为贾里德建议,但我会做到这一点略有不同:

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

编辑:作为建议,这里是完整的例子。这不是完全一样丹尼斯的,但...我已经做了一些改动:)的

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

在我看来,基于这个例子,它看起来很好。您可以通过更换重构甚至更多:

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

有:

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

您可以通过链接选择(图)去拉姆达一路凡(过滤器),而不是多个FOR循环和IF语句

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

基本上,你要多想declaratively代替imperatively与lambda一起工作时。它会帮助你编写更优雅的代码。

2

编写以下代码而不是使用委托关键字更具有惯用性。但它并没有改变基础功能。

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

另外,我觉得它更可读传递给ForEach改写为以下

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

这不会编译除非你有一个foreach扩展方法捡到一些可枚举善良。我也喜欢在行首写上我的点:) – 2009-04-23 18:38:02

+0

@Jon,我很习惯我的自定义LINQ方法,我忘记它们默认情况下不存在。已更新以避免我不拥有的扩展方法。我老实说在点之前或点之后来回点。我以前的偏好是点。但有些语言我用需要的字符为(PowerShell和VB.Net)之后,所以我漂来回;) – JaredPar 2009-04-23 18:48:54

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键代表类型,如果你愿意,但在这种情况下不那么简单。 此外,我会返回一个IEnumerable<WhatHappened>而不是一个列表,但它都是关于上下文。

1

这里有一个LINQ的免费解决方案:

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

警告

这并不是最高效的解决方案,因为它会重复两次。

0

我无法捉摸的代码的目的。但是在这里去。
使用代表链接 更新:和乔恩ñ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>(); 
}