Pre:Pattern match variable scope,但我想更多地了解分配行为。
我做了以下测试。
在F1中,似乎i
在范围内但未分配,我可以通过F2理解它。
但F3的情况让我感到很困惑,因为F2无法解释。
然后在F4中它显示!
在这种情况下没有影响。
// inside a class
object o = 1;
void F0() { // normal usage
if(o is int i)
WriteLine(i);
}
void F1() {
if (o is int i)
WriteLine(i);
else
WriteLine(i); // Use of unassigned local variable 'i'
WriteLine(i); // the same as above
}
void F2() {
int i;
if (o is int) {
i = (int)o; // just for simulation because 'as' can't unbox
WriteLine(i);
}
else
WriteLine(i); // Use of unassigned local variable 'i'
WriteLine(i); // Use of unassigned local variable 'i'
}
void F3() {
if (!(o is int i))
WriteLine(i); // Use of unassigned local variable 'i'
else
WriteLine(i); // compile
WriteLine(i); // Use of unassigned local variable 'i'
}
void F4() {
_ = !(o is int i);
Console.WriteLine(i); // Use of unassigned local variable 'i'
_ = o is int i;
Console.WriteLine(i); // Use of unassigned local variable 'i'
}
我只能得出结论,这个语法对if
的处理方式不同,如果if condition
为真,它将在if true
的范围内分配,否则它将在if else
的范围内分配。
我的理解是否正确?(我猜不是
让我们仔细看下面的声明:
o is int i
如果o
可以转换为int
类型,则此语句将返回true
并将设置i
变量。如果没有,它将返回false
并且i
变量将不会被初始化。此外,在if语句中使用此类代码会将变量移动到外部作用域。
让我们来看看你的方法:
void F1() {
if (o is int i)
WriteLine(i); // i was initialized, because o is int i returned true
else
WriteLine(i); // i was NOT initialized, so you have using of unassigned local variable 'i' here
WriteLine(i); // the same as above, because i wasn't initialized in all code paths before this statement
}
void F2() {
int i;
if (o is int) {
i = (int)o; // just for simulation because 'as' can't unbox
WriteLine(i); // i was initialized in previous line
}
else
WriteLine(i); // o is not int, so i wasn't initialized => using of unassigned local variable 'i'
WriteLine(i); // i wasn't initialized in all code paths, using of unassigned local variable 'i'
}
void F3() {
if (!(o is int i))
WriteLine(i); // Using of unassigned local variable 'i' because o can't be casted to int => !(o is int i)
else
WriteLine(i); // compile - i was initialized
WriteLine(i); // you wrote this statement can be compiled, in fact not, because i is not initialized in all code paths
}
void F4() {
_ = (!(o is int i));
Console.WriteLine(i); // Use of unassigned local variable 'i', because in case of unsuccessful casting i won't be intialized.
}
来自spec for patterns in C# 7.0:
Scope of pattern variables
在模式中声明的变量的范围如下:
- 如果模式是案例标签,则变量的范围是案例块。
否则,变量在is_pattern表达式中声明,其作用域基于紧接着包含is_pattern表达式的表达式的构造,如下所示:
- 如果表达式位于表达式的lambda中,则其范围是lambda的主体。
- 如果表达式位于表达式身体方法或属性中,则其范围是方法或属性的主体。
- 如果表达式在
when
子句的catch
子句中,则其范围是catch
子句。- 如果表达式在iteration_statement中,则其范围就是该语句。
- 否则,如果表达式是某种其他语句形式,则其作用域是包含该语句的作用域。
为了确定范围,embedded_statement被认为是在其自己的范围内。例如,if_statement的语法是
if_statement : 'if' '(' boolean_expression ')' embedded_statement | 'if' '(' boolean_expression ')' embedded_statement 'else' embedded_statement ;
因此,如果if_statement的受控语句声明了一个模式变量,则其范围仅限于embedded_statement:
if (x) M(y is var z);
在这种情况下,
z
的范围是嵌入式语句M(y is var z);
。其他情况是由于其他原因的错误(例如,在参数的默认值或属性中,这两个都是错误,因为这些上下文需要常量表达式)。
在C#7.3中,我们添加了以下可以声明模式变量的上下文: - 如果表达式在构造函数初始值设定项中,则其作用域是构造函数初始值设定项和构造函数体。 - 如果表达式在字段初始值设定项中,则其范围是出现的equals_value_clause。 - 如果表达式位于指定要转换为lambda主体的查询子句中,则其范围就是该表达式。