[英]c# lambda expression - add delegate results to generic list
Question: I have just wrote my first code using c# lambda expressions. 问题:我刚刚使用c#lambda表达式编写了我的第一个代码。 It works, but I am not sure if this is the best way to do it. 它可以工作,但是我不确定这是否是最好的方法。 Any recommendations on a better way to do the lambda expression? 有什么建议可以更好地表达lambda吗? It seems odd to have numerous lines of code in the expression like I do below. 像我下面所做的那样,在表达式中包含很多代码行似乎很奇怪。
Background: I have a generic list of delegates. 背景:我有一个通用的代表列表。 Each delegate function returns an enum value indicating what happened in the function. 每个委托函数都返回一个枚举值,指示该函数中发生了什么。 Upon evaluation of the delegate, I need to add the enum to a List if it was not a specific enum value. 在评估委托后,如果不是特定的枚举值,则需要将枚举添加到列表中。
Disclaimer: Code here is very generic, the real code actually does stuff in the delegates to determine the return value! 免责声明:这里的代码非常通用,实际的代码实际上是在委托中进行填充以确定返回值!
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;
}
}
Note: I originally had the lambda like adding all the items (see below), then removing the ones I didn't want (WhatHappened.Nothing). 注意:我最初有lambda,就像添加所有项目(请参阅下文),然后删除不需要的项目(WhatHappened.Nothing)。
CheckValues.ForEach(x => returnValue.Add(x()));
Okay, a few suggestions: 好的,有几点建议:
del
. 不要叫你的委托del
。 In this case, I'd use Func<WhatHappened>
- but if you do want to declare your own delegate type, give it a more descriptive name, and obey the .NET naming conventions. 在这种情况下,我将使用Func<WhatHappened>
-但是如果您确实想声明自己的委托类型,请给它一个更具描述性的名称,并遵守.NET命名约定。 Instead of using anonymous methods to add to CheckValues
, you can just use: 除了使用匿名方法添加到CheckValues
,您还可以使用:
CheckValues.Add(method1); CheckValues.Add(method2);
The compiler will convert the method groups into delegates. 编译器会将方法组转换为委托。
I'd recommend not using Pascal case for a local variable name to start with. 我建议不要使用Pascal大小写作为开头的局部变量名称。
returnValues
isn't really doing anything for you - just call the List<T>
constructor as normal, or use my code below which doesn't require a local variable to start with. 您的returnValues
集合初始returnValues
设定项实际上并没有为您做任何事情-只需正常调用List<T>
构造函数,或使用下面的我的代码即可,而该代码不需要以本地变量开头。 Otherwise you can indeed use LINQ as Jared suggests, but I'd do it slightly differently: 否则,您确实可以按照Jared的建议使用LINQ,但是我会做些微的不同:
return CheckValues.Select(x => x()) .Where(wh => wh != WhatHappened.Nothing) .ToList();
EDIT: As suggested, here's the full example. 编辑:按照建议,这是完整的示例。 It's not quite the same as Denis's though... I've made a couple of changes :) 不过,它与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();
}
(I'm assuming that method1
and method2
have been renamed to fit the naming convention. Of course in real life I'm sure they'd have more useful names anyway...) (我假设对method1
和method2
进行了重命名以符合命名约定。当然,在现实生活中,我肯定他们会使用更多有用的名称...)
You can go lambda all the way by chaining Select (map) and Where (filter) instead of multiple FOR loops and IF statements 通过链接Select(映射)和Where(过滤器),而不是多个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);
Basically, you should think more declaratively instead of imperatively when work ing with lambdas. 基本上,在处理lambda时,您应该更具声明性,而不是命令性 。 It'll help you write more elegant code. 它可以帮助您编写更精美的代码。
I would simply use Linq, but that's just me: 我只会使用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();
}
Note that you can also use Func instead of declaring a Delegate type if you want, but that's less terse in that case. 请注意,如果需要,也可以使用Func而不是声明Delegate类型,但是在这种情况下,它不那么简洁。 Also, I'd return an IEnumerable<WhatHappened>
instead of a List, but it's all about the context. 另外,我将返回IEnumerable<WhatHappened>
而不是List,但这全都与上下文有关。
It's a bit more idiomatic to write the following instead of using the delegate keyword. 编写以下代码而不是使用委托关键字,这有点习惯。 It doesn't change the underlying functionality though. 它不会改变底层功能。
CheckValues.Add( () => method1() );
Also, I find it more readable to rewrite the ForEach as the following 另外,我发现重写ForEach更具可读性,如下所示
CheckValues = CheckValues.
Select(x => x()).
Where(wh => wh != WhatHappened.Nothing ).
ToList();
In my opinion, based on the example, it looks fine. 我认为,基于该示例,它看起来不错。 You could refactor even more by replacing: 您可以通过替换以下内容来进一步重构:
CheckValues.Add(delegate { return method1(); });
CheckValues.Add(delegate { return method2(); });
with: 与:
CheckValues.Add(() => WhatHappened.Nothing);
CheckValues.Add(() => WhatHappened.ThingA);
Here's a LINQ-free solution: 这是不使用LINQ的解决方案:
return CheckValues
.ConvertAll<WhatHappened>(x => x())
.FindAll(y => y != WhatHappened.Nothing);
caveat 警告
This is not the most performant solution, as it would iterate twice. 这不是性能最高的解决方案,因为它会迭代两次。
I can't fathom the purpose of the code.. however here goes. 我无法理解代码的目的..但是这里。
Used delegate chaining Update: and picked up some Enumerable goodness from Jon n Jared's posts 二手委托链接更新:并从乔恩·贾里德(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>();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.