lambda 表达式中的 C# 切换
Posted
技术标签:
【中文标题】lambda 表达式中的 C# 切换【英文标题】:C# switch in lambda expression 【发布时间】:2010-11-28 19:26:47 【问题描述】:是否可以在 lambda 表达式中进行切换?如果不是,为什么? Resharper 将其显示为错误。
【问题讨论】:
它可以编译吗?我不会使用 Resharper 作为您对有效语法的最终决定。 当然不是,编译后的错误与 resharper 显示的输出相同:无法将带有语句体的 lambda 表达式转换为表达式树。 注:我不知道什么是语句体。 “我不知道语句体是什么”——这就是以 / 大括号开头的 lambda 之间的区别(它 always 编译为匿名方法),以及不支持的 lambda(可以编译为匿名方法或表达式树) @Jeff - 当然,编译器也不是最终的决定 - 但它肯定比尝试检查规范更容易;-p 特别是表达式树翻译的细节是众所周知,在 C# 3.0 / C# 4.0 规范中缺失。 【参考方案1】:你可以在语句块中使用 lambda:
Action<int> action = x =>
switch(x)
case 0: Console.WriteLine("0"); break;
default: Console.WriteLine("Not 0"); break;
;
但你不能在“单一表达式 lambda”中做到这一点,所以这是无效的:
// This won't work
Expression<Func<int, int>> action = x =>
switch(x)
case 0: return 0;
default: return x + 1;
;
这意味着您不能在表达式树中使用 switch(至少由 C# 编译器生成;我相信 .NET 4.0 至少在库中支持它)。
【讨论】:
是的,确实似乎问题是我想要一个表达式树。有没有比 if els if o a functino 更好的解决方法? 一个小修正(事后看来……后见之明有多大好处:-))。 C# 4.0 编译器仍然无法构建“复杂”Expressions
(使用 if
、while
...),但您可以通过使用 Expression
类来构建它们。这两件事是解耦的。事后诸葛亮:OP 询问了表达式树。第二个 action
应该是 Expression<Func<int, int>>
以表明您确实需要表达式树而不是委托。
已经有一段时间了,C# 8 添加了 switch 表达式,允许您使用 Func<int, int> action = x => x switch 0 => 0, _ => x + 1 ;
但是,由于某种原因,它仍然不允许在表达式树中使用 Expression<Func<int, int>> action = x => x switch 0 => 0, _ => x + 1 ;
【参考方案2】:
在纯 Expression
(在 .NET 3.5 中)中,您可以获得的最接近的是复合条件:
Expression<Func<int, string>> func = x =>
x == 1 ? "abc" : (
x == 2 ? "def" : (
x == 3 ? "ghi" :
"jkl")); /// yes, this is ugly as sin...
不好玩,尤其是当它变得复杂时。如果您的意思是带有语句体的 lamda 表达式(仅用于 LINQ-to-Objects),那么大括号内的任何内容都是合法的:
Func<int, string> func = x =>
switch (x)
case 1: return "abc";
case 2: return "def";
case 3: return "ghi";
default: return "jkl";
;
当然,您可以将工作外包;例如,LINQ-to-SQL 允许您将标量 UDF(在数据库中)映射到数据上下文(实际未使用)上的方法 - 例如:
var qry = from cust in ctx.Customers
select new cust.Name, CustomerType = ctx.MapType(cust.TypeFlag) ;
其中MapType
是在数据库服务器上执行工作的 UDF。
【讨论】:
你可以在你的第一个代码中省略括号 - 结果是 much 不那么难看,我有时会使用它。诚然,这需要一点时间来适应,但它的可读性并不比同等的switch
块低(我认为不那么好)。
没有括号我有时会迷路? / : 等等...但是是的,没有它们它也可以工作;-p
@MarcGravell 对于.Net 4.0 中的纯Expression
来说还有什么更好的吗?
@ken2k 是和否; Expression
API 包括完整的块支持,包括 Expression.Switch
- 但是,这里的问题是关于 lambdas; C# lambda-to-Expression
编译器没有改变,现在支持更广泛的Expression
语法。
@MarcGravell 感谢您提供信息。我将使用您在第一个代码中提供的语法,这是我发现的最易读的缩进:) 让我们希望 C# 语言/编译器的下一个版本能够提供更好的东西。【参考方案3】:
是的,它可以工作,但是您必须将代码放在一个块中。示例:
private bool DoSomething(Func<string, bool> callback)
return callback("FOO");
然后,调用它:
DoSomething(val =>
switch (val)
case "Foo":
return true;
default:
return false;
);
【讨论】:
【参考方案4】:嗯,我看不出这不应该起作用的原因。请注意您使用的语法
param =>
// Nearly any code!
delegate (param)
// Nearly any code!
param => JustASingleExpression (No switches)
【讨论】:
【参考方案5】:我也查过:-)
[Test]
public void SwitchInLambda()
TakeALambda(i =>
switch (i)
case 2:
return "Smurf";
default:
return "Gnurf";
);
public void TakeALambda(Func<int, string> func)
System.Diagnostics.Debug.WriteLine(func(2));
工作得很好(输出“Smurf”)!
【讨论】:
因为那不是 Lambda 表达式。 Lambda 表达式 的类型为Expression<Func<int, string>>
。那是一个 Lambda 函数。尝试更改 TakeALambda 的输入参数,看看有什么不同。【参考方案6】:
我刚学这个:
(model) =>
switch(model.SentInvoiceTypeId)
case 1:
return "1 asdf";
case 2:
return "2 asdf";
case 3:
return "3 asdf ";
case 4:
return "4 asdf ";
default:
return "asdf";
只需放在“模型”() 之间并在 中添加您的代码,记得有一个返回。 我不确定在哪个版本的 C# 中可以工作,在这个例子中是 C# 7.0
我希望这个答案可以帮助别人。
【讨论】:
以上是关于lambda 表达式中的 C# 切换的主要内容,如果未能解决你的问题,请参考以下文章