如何将临时变量声明为 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# 表达式?的主要内容,如果未能解决你的问题,请参考以下文章

WebForm中c#中如何将字符串声明为一个变量或控件名

c# 在 Lambda 表达式中声明变量

如何将数据设置为临时表中的变量?

C#关键字 const与readonly

C#中的var理解

如何声明 Linq 表达式变量以便将其作为 dbParameter 处理