上一步: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
为true,则将在if true
的范围内进行分配,否则将在{{1 }}的范围。
我的理解正确吗?(我想不是
答案 0 :(得分:1)
来自spec for patterns in C# 7.0:
模式变量的范围
在模式中声明的变量的范围如下:
- 如果模式是大小写标签,则变量的范围为 case块。
否则,该变量在 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主体的查询子句中,则其作用域就是该表达式。
答案 1 :(得分:0)
让我们仔细看看以下陈述:
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.
}