简体   繁体   English

如何强制 throw 成为语句而不是表达式(在 lambda 表达式中)?

[英]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. 从 C# 7.0 开始 throw关键字既可以用作表达式,也可以用作语句,这很好。 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)甚至像这样(带有语句 lambda)

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

the M(Func<>) overload is selected by the compiler indicating that the throw is here considered as an expression.编译器选择了 M(Func<>) 重载,表明 throw 在这里被视为一个表达式。 How can I elegantly and intent-clear force the compiler to select the M(Action) overload?我怎样才能优雅而明确地强制编译器选择 M(Action) 重载?

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.但是返回语句的原因似乎并不明显,并且冒着被下一个开发人员更改的风险,特别是因为 Resharper 警告了无法访问的代码。

(Of course I can change the method naming to avoid overloading, but that is not the question. :-) (当然我可以更改方法命名以避免重载,但这不是问题。:-)

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).这与 lambda 是语句 lambda 还是表达式 lambda 无关(正如您将 lambda 从表达式 lambda 更改为语句 lambda 并且行为没有改变最简洁地展示的那样)。

There are numerous ways you can make a lambda match multiple possible overloads.有多种方法可以使 lambda 匹配多个可能的重载。 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).这是特定于较新版本的,但自 C# 1.0 以来已经应用了其他方法(并且自从引入匿名方法以来,需要存在匿名方法的特定处理和由此产生的重载决议消歧)。

The rules for determining which overload is called are spelled out in section 7.5.3.3 of the C# specs.确定调用哪个重载的规则在 C# 规范的第 7.5.3.3 节中有详细说明。 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;无论是语句 lambda 还是表达式 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.因此,您要么需要通过使匿名方法对Func<int>无效来防止重载匹配,要么显式强制类型为Action ,以便编译器不会自行消除歧义。

You could add a cast to for Action , although it does get a bit LISP'y with all the parentheses:您可以为Action添加一个演员表,尽管它确实有点LISP'y与所有括号:

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

Not ideal, but if you want maximum clarity:不理想,但如果你想要最大的清晰度:

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

One possible approach is to use named parameters:一种可能的方法是使用命名参数:

public static void M(Action action) { /* do stuff */ }

public static void M(Func<int> func) { /* do stuff */ }

public static void Main()
{
    M(action: () => throw new Exception());
}

This should probably be documented in the code so as not to surprise the next developer to come along, and as noted in the comments write an appropriate automated test to verify the correct overload is called.这可能应该记录在代码中,以免让下一个开发人员感到惊讶,并且如注释中所述,编写适当的自动化测试来验证调用了正确的重载。

To add to all the reasonable answers given, here's a charming unreasonable answer:为了添加所有给出的合理答案,这里有一个迷人的不合理的答案:

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

That one should bake the noodle of any maintenance programmers who come along, and they'll leave it alone.那个应该烤任何出现的维护程序员的面条,他们会不理会它。 See if you can figure out why it works.看看你是否能弄清楚它为什么起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM