C# 7.0 模式匹配变量的作用域和赋值语法
C# 7.0 pattern matching variables' scope and assignment syntax
前:,但我想了解更多关于赋值行为的信息。
我做了以下测试
在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
类型,此语句将设置 return true
和 i
变量。如果没有,它将 return 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
The scope of a variable declared in a pattern is as follows:
- If the pattern is a case label, then the scope of the variable is the case block.
Otherwise the variable is declared in an is_pattern expression, and its scope is based on the construct immediately enclosing the expression containing the is_pattern expression as follows:
- If the expression is in an expression-bodied lambda, its scope is the body of the lambda.
- If the expression is in an expression-bodied method or property, its scope is the body of the method or property.
- If the expression is in a
when
clause of a catch
clause, its scope is that catch
clause.
- If the expression is in an iteration_statement, its scope is just that statement.
- Otherwise if the expression is in some other statement form, its scope is the scope containing the statement.
For the purpose of determining the scope, an embedded_statement is considered to be in its own scope. For example, the grammar for an if_statement is
if_statement
: 'if' '(' boolean_expression ')' embedded_statement
| 'if' '(' boolean_expression ')' embedded_statement 'else' embedded_statement
;
So if the controlled statement of an if_statement declares a pattern variable, its scope is restricted to that embedded_statement:
if (x) M(y is var z);
In this case the scope of z
is the embedded statement M(y is var z);
.
Other cases are errors for other reasons (e.g. in a parameter's default value or an attribute, both of which are an error because those contexts require a constant expression).
In C# 7.3 we added the following contexts in which a pattern variable may be declared:
- If the expression is in a constructor initializer, its scope is the constructor initializer and the constructor's body.
- If the expression is in a field initializer, its scope is the equals_value_clause in which it appears.
- If the expression is in a query clause that is specified to be translated into the body of a lambda, its scope is just that expression.
前:
我做了以下测试
在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
类型,此语句将设置 return true
和 i
变量。如果没有,它将 return 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
The scope of a variable declared in a pattern is as follows:
- If the pattern is a case label, then the scope of the variable is the case block.
Otherwise the variable is declared in an is_pattern expression, and its scope is based on the construct immediately enclosing the expression containing the is_pattern expression as follows:
- If the expression is in an expression-bodied lambda, its scope is the body of the lambda.
- If the expression is in an expression-bodied method or property, its scope is the body of the method or property.
- If the expression is in a
when
clause of acatch
clause, its scope is thatcatch
clause.- If the expression is in an iteration_statement, its scope is just that statement.
- Otherwise if the expression is in some other statement form, its scope is the scope containing the statement.
For the purpose of determining the scope, an embedded_statement is considered to be in its own scope. For example, the grammar for an if_statement is
if_statement : 'if' '(' boolean_expression ')' embedded_statement | 'if' '(' boolean_expression ')' embedded_statement 'else' embedded_statement ;
So if the controlled statement of an if_statement declares a pattern variable, its scope is restricted to that embedded_statement:
if (x) M(y is var z);
In this case the scope of
z
is the embedded statementM(y is var z);
.Other cases are errors for other reasons (e.g. in a parameter's default value or an attribute, both of which are an error because those contexts require a constant expression).
In C# 7.3 we added the following contexts in which a pattern variable may be declared: - If the expression is in a constructor initializer, its scope is the constructor initializer and the constructor's body. - If the expression is in a field initializer, its scope is the equals_value_clause in which it appears. - If the expression is in a query clause that is specified to be translated into the body of a lambda, its scope is just that expression.