问题:我刚刚使用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()));
答案 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();
}
(我假设method1
和method2
已经重命名以符合命名惯例。当然在现实生活中我肯定他们还有更多有用的名字......)
答案 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>();
}