0

Is there a way to declare temporary variables in expressions for reusing intermediary results?

The motivation is to still be able to use fluent style call chains and expression bodied methods when you need to use a calculated result more than once in logic or transformations e.g.

public static string Foo(IBar bar)
{
    var result = bar.LongCalculation();

    return result.HasError
        ? throw new Exception()
        : result.ToString();
}

I thought I might be able to use let/select linq query keywords but it doesn't seem possible without a from clause e.g.

public static string Foo(IBar bar) =>
    let result = bar.LongCalculation()                
    select result.HasError
        ? new Exception()
        : result.ToString();
Johnny
  • 8,939
  • 2
  • 28
  • 33
daw
  • 1,959
  • 1
  • 20
  • 25
  • Why you don't call a method in your expression bodied method like `LongCalculationSafe`? Then you could use whatever code you need there. – Tim Schmelter Jan 14 '19 at 10:20
  • 1
    Why do you want to use an expression bodied method? It's just syntax sugar that can be used when the body is a one-liner. If you need multiple lines, just use the regular method syntax. – user247702 Jan 14 '19 at 10:39
  • I prefer the functional flowing style - it's the direction c# is going in and interested to know if it has a solution - it's frustrating to have to rewrite a method to be cury braced because of a detail in the logic/transformation needs to reuse a temporary. – daw Jan 14 '19 at 10:54
  • 1
    LINQ makes no sense here. LINQ is effectively a "better foreach" in the sense that it works on **collections** and iterates over them. But that's not the case here, you're working with a singular `result` object. LINQ only deals with collection iteration so even if you hacked it in (e.g. by putting your singular object in a list), it wouldn't serve a meaningful purpose. – Flater Jan 14 '19 at 11:02

3 Answers3

3

You could use an Extension method:

public static class LongCalculationExtensions
{
    public static ILongCalculationResult ThrowIfHasError(this ILongCalculationResult result)
    {
       if(result.HasError) throw new Exception("Your exception here");

       return result;
    }
}

Then you could use it like this:

public static string Foo(IBar bar) => bar.LongCalculation().ThrowIfHasError().ToString();   
nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • Interesting thanks. This is good for handling specifc cases that are frequent but not the general case. btw the extension method can use throw expressions so can be expression bodied too. – daw Jan 14 '19 at 10:55
1

My previous answer for Pipe required a lambda, a better solution with less overhead is to take advantage of an inline out declaration:

public static class FunctionalExtensions
{
    public static T Assign<T>(this T o, out T result) =>
        result = o;
}

And call it like this

public static string Foo(IBar bar) =>
    bar.LongCalculation()
       .Assign(out var result)
       .HasError
           ? throw new Exception()
           : result.ToString();
daw
  • 1,959
  • 1
  • 20
  • 25
0

My preferred approach is Timothy Shields answer here:

How to "let" in lambda expression?

Create an extension-method similar to F#'s pipe operator:

public static class FunctionalExtensions
{
    public static TResult Pipe<T, TResult>(this T value, Func<T, TResult> func) =>
        func(value);
}

And call it like this

public static string Foo(IBar bar) =>
    bar.LongCalculation()
       .Pipe(result => result.HasError
           ? throw new Exception()
           : result.ToString();
daw
  • 1,959
  • 1
  • 20
  • 25