Как я могу заставить бросок быть оператором, а не выражением (в лямбда-выражении)? - PullRequest
0 голосов
/ 16 января 2019

Начиная с 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());

или даже так (с лямбда-выражением)

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

Перегрузка M (Func <>) выбирается компилятором, указывая, что бросок здесь рассматривается как выражение. Как я могу изящно и с явным намерением заставить компилятор выбрать перегрузку M (Action)?

Один из способов сделать это - это

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

но причина оператора return кажется неочевидной, и существует риск изменения следующего разработчика, тем более что Resharper предупреждает о недоступном коде.

(Конечно, я могу изменить название метода, чтобы избежать перегрузки, но это не вопрос.: -)

Ответы [ 4 ]

0 голосов
/ 16 января 2019

Чтобы добавить ко всем разумным ответам, вот очаровательный неразумный ответ:

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

Тот, кто должен испечь лапшу всех программистов, которые придут, и они оставят это в покое. Посмотрим, сможете ли вы выяснить, почему это работает.

0 голосов
/ 16 января 2019

Один из возможных подходов - использовать именованные параметры:

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

Это, вероятно, должно быть задокументировано в коде, чтобы не удивлять следующего разработчика, и, как отмечено в комментариях, написать соответствующий автоматический тест для проверки правильности вызванной перегрузки.

0 голосов
/ 16 января 2019

Это не имеет ничего общего с тем, является ли лямбда-выражение лямбда-выражением или лямбда-выражением (как наиболее кратко показано, когда вы заменяете лямбда-выражение лямбда-выражения на выражение-лямбда и поведение не меняется).

Существует множество способов, позволяющих сделать лямбда-выражение совпадающим с несколькими возможными перегрузками.Этот специфичен для более новых версий, но другие методы применялись начиная с C # 1.0 (а специфическая обработка анонимных методов и устранение неоднозначности разрешения перегрузки должна существовать с момента введения анонимных методов).

Правила определения того, какая перегрузка вызывается, изложены в разделе 7.5.3.3 спецификации C #.В частности, когда параметр является анонимным методом, он всегда предпочитает перегрузку, у которой делегат (или выражение) имеет возвращаемое значение, а не возвращаемое значение.Это будет верно, будь то выражение лямбда или выражение лямбда;это относится к любой форме анонимной функции.

Таким образом, необходимо либо предотвратить сопоставление обеих перегрузок, сделав анонимный метод недопустимым для Func<int>, либо явно принудительно принудительно указав тип Action, чтобы компилятор не устранял неоднозначность сам по себе.

0 голосов
/ 16 января 2019

Вы можете добавить приведение к для Action, хотя он получает немного LISP'y со всеми круглыми скобками:

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

Не идеально, но если вы хотите максимальной ясности:

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