如何将临时变量声明为 C# 表达式?
Posted
技术标签:
【中文标题】如何将临时变量声明为 C# 表达式?【英文标题】:How to declare temporary variables as C# expressions? 【发布时间】:2019-06-08 07:35:22 【问题描述】:有没有办法在表达式中声明临时变量以重用中间结果?
动机是当您需要在逻辑或转换中多次使用计算结果时,仍然能够使用流畅的调用链和表达式主体方法,例如
public static string Foo(IBar bar)
var result = bar.LongCalculation();
return result.HasError
? throw new Exception()
: result.ToString();
我认为我可以使用 let/select linq 查询关键字,但如果没有 from 子句,这似乎是不可能的,例如
public static string Foo(IBar bar) =>
let result = bar.LongCalculation()
select result.HasError
? new Exception()
: result.ToString();
【问题讨论】:
为什么不调用像LongCalculationSafe
这样的表达式主体方法中的方法?然后你可以在那里使用你需要的任何代码。
为什么要使用表达式体法?当正文是单行时,它只是可以使用的语法糖。如果您需要多行,只需使用常规方法语法即可。
我更喜欢函数式流动风格——这是 c# 的方向,并且有兴趣知道它是否有解决方案——因为在逻辑/转换需要重用一个临时的。
LINQ 在这里毫无意义。 LINQ 实际上是一个“更好的 foreach”,因为它适用于 collection 并迭代它们。但这不是这里的情况,您正在使用一个单一的result
对象。 LINQ 只处理集合迭代,所以即使你入侵它(例如,通过将你的单个对象放在一个列表中),它也没有任何意义。
【参考方案1】:
您可以使用扩展方法:
public static class LongCalculationExtensions
public static ILongCalculationResult ThrowIfHasError(this ILongCalculationResult result)
if(result.HasError) throw new Exception("Your exception here");
return result;
那么你可以这样使用它:
public static string Foo(IBar bar) => bar.LongCalculation().ThrowIfHasError().ToString();
【讨论】:
有趣的谢谢。这对于处理常见但不是一般情况的特定情况很有用。顺便说一句,扩展方法可以使用 throw 表达式,因此也可以是表达式。【参考方案2】:我之前对Pipe
的回答需要一个 lambda,一个开销更少的更好解决方案是利用内联输出声明:
public static class FunctionalExtensions
public static T Assign<T>(this T o, out T result) =>
result = o;
然后这样称呼它
public static string Foo(IBar bar) =>
bar.LongCalculation()
.Assign(out var result)
.HasError
? throw new Exception()
: result.ToString();
【讨论】:
【参考方案3】:我的首选方法是 Timothy Shields 在这里回答:
How to "let" in lambda expression?
创建一个类似于 F# 的管道运算符的扩展方法:
public static class FunctionalExtensions
public static TResult Pipe<T, TResult>(this T value, Func<T, TResult> func) =>
func(value);
然后这样称呼它
public static string Foo(IBar bar) =>
bar.LongCalculation()
.Pipe(result => result.HasError
? throw new Exception()
: result.ToString();
【讨论】:
以上是关于如何将临时变量声明为 C# 表达式?的主要内容,如果未能解决你的问题,请参考以下文章