Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I force a throw to be a statement and not an expression (in a lambda expression)?

Starting from C# 7.0 the throw keyword can be used both as an expression and as a statement, which is nice. Though, consider these overloads

public static void M(Action doIt) { /*use doIt*/ }
public static void M(Func<int> doIt) { /*use doIt*/ }

When invoking like this

M(() => throw new Exception());

or even like this (with a statement lambda)

M(() => { throw new Exception(); });

the M(Func<>) overload is selected by the compiler indicating that the throw is here considered as an expression. How can I elegantly and intent-clear force the compiler to select the M(Action) overload?

One way to do it is this

M(() => { throw new Exception(); return; });

but the reason for the return statement seems non-obvious, and runs the risk of being changed by the next developer especially since Resharper warns about the unreachable code.

(Of course I can change the method naming to avoid overloading, but that is not the question. :-)

like image 536
Ulf Åkerstedt Avatar asked Jan 15 '19 23:01

Ulf Åkerstedt


People also ask

What are lambda expression in c#?

A lambda expression with an expression on the right side of the => operator is called an expression lambda. An expression lambda returns the result of the expression and takes the following basic form: C# Copy. (input-parameters) => expression. The body of an expression lambda can consist of a method call.

What is lambda expression in Linq?

Advertisements. The term 'Lambda expression' has derived its name from 'lambda' calculus which in turn is a mathematical notation applied for defining functions. Lambda expressions as a LINQ equation's executable part translate logic in a way at run time so it can pass on to the data source conveniently.

What is lambda expression in C# with example?

The expression num => num * 5 is a lambda expression. The => operator is called the "lambda operator". In this example, num is an input parameter to the anonymous function, and the return value of this function is num * 5 . So when multiplyByFive is called with a parameter of 7 , the result is 7 * 5 , or 35 .


1 Answers

This has nothing to do with whether the lambda is a statement lambda or an expression lambda (as is most succinctly shown by you changing the lambda from an expression lambda to a statement lambda and the behavior not changing).

There are numerous ways you can make a lambda match multiple possible overloads. This one is specific to newer versions, but other methods have applied since C# 1.0 (and the specific handling of anonymous methods and the resulting overload resolution disambiguation has needed to exist since the introduction of anonymous methods).

The rules for determining which overload is called are spelled out in section 7.5.3.3 of the C# specs. Specifically, when the parameter is an anonymous method, it will always prefer the overload who's delegate (or expression) has a return value over one that has no return value. This will be true whether it's a statement lambda or expression lambda; it applies to any form of anonymous function.

Thus you either need to prevent both overload from matching by making the anonymous method not valid for a Func<int>, or explicitly force the type to be an Action so the compiler is not disambiguating it itself.

like image 144
Servy Avatar answered Sep 30 '22 04:09

Servy