簡體   English   中英

如何強制 throw 成為語句而不是表達式(在 lambda 表達式中)?

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

從 C# 7.0 開始 throw關鍵字既可以用作表達式,也可以用作語句,這很好。 雖然,考慮這些重載

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

像這樣調用時

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

甚至像這樣(帶有語句 lambda)

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

編譯器選擇了 M(Func<>) 重載,表明 throw 在這里被視為一個表達式。 我怎樣才能優雅而明確地強制編譯器選擇 M(Action) 重載?

一種方法是這樣

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

但是返回語句的原因似乎並不明顯,並且冒着被下一個開發人員更改的風險,特別是因為 Resharper 警告了無法訪問的代碼。

(當然我可以更改方法命名以避免重載,但這不是問題。:-)

這與 lambda 是語句 lambda 還是表達式 lambda 無關(正如您將 lambda 從表達式 lambda 更改為語句 lambda 並且行為沒有改變最簡潔地展示的那樣)。

有多種方法可以使 lambda 匹配多個可能的重載。 這是特定於較新版本的,但自 C# 1.0 以來已經應用了其他方法(並且自從引入匿名方法以來,需要存在匿名方法的特定處理和由此產生的重載決議消歧)。

確定調用哪個重載的規則在 C# 規范的第 7.5.3.3 節中有詳細說明。 具體來說,當參數是匿名方法時,它總是更喜歡委托(或表達式)有返回值的重載,而不是沒有返回值的重載。 無論是語句 lambda 還是表達式 lambda,這都是正確的; 它適用於任何形式的匿名函數。

因此,您要么需要通過使匿名方法對Func<int>無效來防止重載匹配,要么顯式強制類型為Action ,以便編譯器不會自行消除歧義。

您可以為Action添加一個演員表,盡管它確實有點LISP'y與所有括號:

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

不理想,但如果你想要最大的清晰度:

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

一種可能的方法是使用命名參數:

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());
}

這可能應該記錄在代碼中,以免讓下一個開發人員感到驚訝,並且如注釋中所述,編寫適當的自動化測試來驗證調用了正確的重載。

為了添加所有給出的合理答案,這里有一個迷人的不合理的答案:

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

那個應該烤任何出現的維護程序員的面條,他們會不理會它。 看看你是否能弄清楚它為什么起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM