C#7.0模式匹配变量的范围和赋值语法

时间:2019-03-16 13:42:52

标签: c# c#-7.0

上一步: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 }}的范围。

我的理解正确吗?(我想不是

2 个答案:

答案 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.
}