Ошибка компилятора С# 7 - соответствие шаблону
По какой-то причине M1()
вызывает ошибку компилятора, а M2()
, что делает то же самое, не вызывает ошибки. Любая идея почему?
Использование false ==
должно быть таким же, как с использованием оператора not, !
.
Использование неназначенной локальной переменной 'i'
class Program {
static void Main(string[] args) {
int x = 8;
M1(x);
M2(x);
} // Main()
public static void M1(Object obj) {
if (false == (obj is int i)) // Causes ERROR on WriteLine
return;
System.Console.WriteLine(i); // Use of unassigned local variable 'i'
}
public static void M2(Object obj) {
if (!(obj is int i)) // OKAY
return;
System.Console.WriteLine(i);
}
} // class Program
Ответы
Ответ 1
Проблема здесь в том, как компилятор обрабатывает "определенно назначенный, когда true". !
инвертирует это; == false
нет. Итак, для кода:
if (!(obj is int i))
return;
System.Console.WriteLine(i);
Компилятор может сделать вывод, что если obj is int i
является ложным, !
инвертирует, что, таким образом, return
произойдет, если это не int
. Поэтому i
может быть безопасно "утечка" в следующий код.
Однако те же правила не относятся к == false
. Несмотря на то, что семантически идентичен человеческому читателю кода, компилятор рассматривает !
и == false
как очень разные вещи. Итак, для:
if (false == (obj is int i))
компилятор блуждает и принимает представление, что он не может знать состояние присваивания i
, поэтому ошибка.
Для обсуждения этого, пожалуйста, см. Неверное "использование неназначенной локальной переменной" для (x is T y) == false
.
Мораль истории: избегайте сравнения с false
и используйте !
при использовании шаблонов С#.
ИЗМЕНИТЬ
Следует отметить, что == false
здесь не является частным случаем. Любое использование ==
устраняет возможность компилятора определить "определенно назначенный, когда true". Например, следующий код компилируется:
object x = 1;
if (!(x is bool y))
return 0;
var z = y;
Но добавьте == true
, и он больше не делает:
object x = 1;
if (!(x is bool y == true))
return 0;
var z = y; // error: use of an unassigned variable
EDIT2
Случайно, для тех, кто использует if (expression == false)
, потому что они находят if (!expression)
трудным для чтения, вам может быть интересно узнать, что синтаксис if !(expression)
рассматривается для С# 8.
Ответ 2
Хорошая находка, вот что я думаю. обратите внимание, что это определенно может быть исправлено, но я пытаюсь найти для этого аргументацию. обратите внимание, что это неточный ответ. просто говоря!
это не просто false ==
, вызывающее эту проблему, но также == true
приводит к тому, что i
становится непригодным в любой ветки, поэтому я пошел дальше и написал это.
var x = obj is int i;
if(x) Console.WriteLine(i);
вы получаете ту же ошибку. как вы можете видеть, если x
истинно, тогда i
должен быть инициализирован, правильно? если вы не начнете гасить значение x
! здесь x
не является константой, поэтому мы не можем гарантировать, что x
всегда остается истинным перед выполнением оператора if.
как компилятор может вычислять постоянные значения и выражения во время компиляции. Я не уверен, что здесь происходит, но я думаю, что
if((obj is int i) == false)
здесь ==
оператор помещает пробел между результатом сопоставления шаблонов и оценивает оператор if, следовательно, ошибку. Я не знаю, почему оператор !
отлично работает, может быть, они оптимизировали эту часть, но забыли оптимизировать это?;)
Я думаю, что это относится к фазе семантического анализа компилятора, его задача - проверить смысл вашего кода и определить, как он выполняется, если что-то не так, если есть возможность поведения undefined или что-то совершенно бессмысленное, он терпит неудачу, и вы получаете ошибку времени компиляции. подробнее о Фазы проектирования компилятора