C# 8 выражение переключателя для методов void - PullRequest
7 голосов
/ 27 мая 2020

Мне известен синтаксис C# 8 switch expression для методов, возвращающих значение, или для сопоставления свойств. Но если нам просто нужно включить строковое значение и выполнить метод, который ничего не возвращает (без возвращаемого типа / void), то как нам go об этом? Я думаю о какой-то форме Fun c, но не уверен в точном синтаксисе. Я знаю, что мы можем сделать это по-старому с помощью обычных операторов case, но я пытался понять, сможем ли мы добиться того же с новым синтаксисом.

Вот пример проблемы

switch (stringvalue)
{
    case "Add": Add(); break;
    case "Subtract": Subtract(); break;
}

может быть так:

stringvalue switch
{
    "Add" => Add(),
    "Subtract" => Subtract()
}
// but this complains that there needs to be assignment on left side for this

Возможно ли это?

1 Ответ

3 голосов
/ 27 мая 2020

TL; DR

Это невозможно. In C# 8 switch expression не может вернуть void. Он должен возвращать значение, и это значение должно быть использовано (присвоено переменной, передано как аргумент методу, возвращено как результат метода, et c.). Но есть обходной путь. Мы можем написать switch expression, которое возвращает delegate (например, типа Action), а затем сразу вызывает его:

(stringValue switch
 {
    "Add" => (Action) Add,
    "Subtract" => Subtract
 })();

Пояснение

Возможно ли это?

В C# 8 это невозможно. Это ограничение описано в C# specification.

Обратимся к C# specification. На страницах Recursive Pattern Matching - Switch Expression и Statements мы можем узнать, что:

  • switch_expression не допускается в качестве expression_statement.

  • expression_statement оценивает данное выражение. Значение, вычисленное выражением, если оно есть, отбрасывается.

Из этих двух операторов мы можем сделать вывод, что switch_expression не может использоваться в контексте expression_statement, и его значение результата не может быть отброшено . Значение результата должно использоваться, например, оно должно быть присвоено переменной, передано методу в качестве аргумента или возвращено как результат метода. Поэтому компилятор жалуется, что switch expression нельзя использовать как оператор.

если нам просто нужно включить строковое значение и выполнить метод, который ничего не возвращает (без возвращаемого типа / void), как мы go об этом? Я думаю о какой-то форме Fun c, но не уверен в точном синтаксисе.

Мы можем использовать следующий подход: написать switch expression, который возвращает delegate, а затем сразу вызывает его . Например:

(stringValue switch
 {
    "Add" => (Action) Add,
    "Subtract" => Subtract
 })();

Этот подход также можно использовать для объявления expression bodied members:

private static void Demo(string str) =>
    (str switch
     {
         "Add" => (Action) Add,
         "Subtract" => Subtract,
         _ => throw new ArgumentOutOfRangeException()
     })();

Вот полный образец .

На мой взгляд, такой обходной путь выглядит некрасиво, и лично я предпочел бы использовать switch-case или if-else вместо такой конструкции.

Возможно, в будущей версии C# это ограничение будет ослаблено ( см. Эту ссылку ):

switch_expression не допускается как expression_statement .

Мы планируем смягчить это в будущих версиях.

Но я не нашел подходящего предложения в csharplang repo.

...