C#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 

这里的问题是编译器处理“当真实时明确分配”的方式。 ! 颠倒了; == false不会。 所以对于代码:

 if (!(obj is int i)) return; System.Console.WriteLine(i); 

编译器可以推断,如果obj is int i是假的,那么! 反转,如果它不是int ,则return 。 因此, i可以安全地“泄漏”到后续代码中。

但是,相同的规则不适用于== false 。 虽然在语义上与代码的人类读者相同,但编译器会对待!== false是非常不同的东西。 因此对于:

 if (false == (obj is int i)) 

编译器阻塞并获取视图,它无法知道i的赋值状态,从而导致错误。

有关此问题的讨论,请参阅错误的“使用未分配的局部变量” (x is T y) == false

故事的寓意:避免与false和使用相比! 使用C#模式时。

编辑

应该注意的是, == 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)正在考虑用于C#8 。

好的发现,这就是我的想法。 请注意,这肯定是可以解决的问题,但我正试图找到它的推理。 请注意,这不是准确的答案。 只是说!

它不仅仅是false ==导致这个问题,而且== true导致i在任何一个分支中变得无法使用,所以我继续写下这个。

 var x = obj is int i; if(x) Console.WriteLine(i); 

你得到同样的错误。 正如你可以看到x是真的那么i应该被初始化,对吗? 除非你开始用x值捣乱! 这里x不是常量因此我们无法保证在执行if语句之前x始终保持为真。

编译器如何在编译时计算常量值和表达式。 我不确定这里发生了什么,但我认为是

if((obj is int i) == false)

这里==运算符在模式匹配的结果和if语句之间设置了一个间隙,因此错误。 我不知道为什么! 运算符工作正常,也许他们优化了那部分但忘了优化这个? ;)

我认为这与编译器的语义分析阶段有关,它的工作是validation代码的含义并确定其执行方式,如果有错误,如果有可能存在未定义的行为或者存在完全没有意义的东西,它会失败并且你得到编译时错误。 阅读有关编译器设计阶段的更多信息