模式匹配和作用域 - If 语句



所以,我一直在绞尽脑汁,或者更确切地说是缺乏以下代码片段:

public static void Main()
{
string a = "sdasd";
object b = (object)a;
object c = (object)a;

if (b is string mystring) {
Console.WriteLine(mystring);
}
if (c is string mystring) {
Console.WriteLine(mystring);
}
}

(https://dotnetfiddle.net/tUTcOR(

尝试编译上述代码将产生编译时错误:

已定义或在此范围内定义了名为"mystring"的局部变量或函数

我被引导相信,在 if 语句的表达式中声明的任何内容都作用域与所述语句的范围相同,因此在上面的例子中,"main"将定义范围。这是有道理的。


参考 MSDN 文档:

public static double ComputeAreaModernIs(object shape)
{
if (shape is Square s)
return s.Side * s.Side;
else if (shape is Circle c)
return c.Radius * c.Radius * Math.PI;
else if (shape is Rectangle r)
return r.Height * r.Length;
// elided
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape));
}

让我们从范围开始详细检查这两个规则。变量 c 仅在第一个 if 语句的 else 分支中起作用。变量 s 在方法 ComputeAreaModernIs 的范围内。这是因为 if 语句的每个分支都为变量建立了一个单独的范围。但是,if 语句本身不会。这意味着在 if 语句中声明的变量与 if 语句(在本例中为方法(位于同一范围内。此行为并非特定于模式匹配,而是变量作用域以及 if 和 else 语句的已定义行为。

变量 c 和 s 在各自的 if 语句为真时赋值,因为 absolute 赋值 when true 机制。

(https://learn.microsoft.com/en-us/dotnet/csharp/pattern-matching(


现在给定上述解释,我想记下两个具体点,并提供另一个代码片段:

这是因为 if 语句的每个分支都为变量建立了一个单独的作用域。

当各自的 if 语句为真时,将赋值变量 c 和 s

public static void Main()
{
string a = "sdasd";
object b = (object)a;
object c = (object)a;

if (b is string mystring) {
Console.WriteLine(mystring);
}else if (c is string mystringg)  {
Console.WriteLine(mystringg);
}else if (c is int mystringg) {
Console.WriteLine(mystringg.ToString());
}

}

(https://dotnetfiddle.net/FFZhyl(

因此,鉴于c is string mystringgc is int mystringg是在单独的范围内定义的(根据上面提到的第一个引号(,并且两者都无法计算为true(要么(,这意味着只有两者中的一个将被初始化(根据上面的第二个引号(,为什么上面的代码不编译?

注意这一段:

这是因为 if 语句的每个分支都为变量建立了一个单独的范围。但是,if 语句本身不会。

这意味着在 if 语句中声明的变量与 if 语句(在本例中为方法(位于同一范围内。此行为并非特定于模式匹配,而是变量作用域以及 if 和 else 语句的已定义行为。

这意味着mystring具有方法范围。 如果你在 Sharplab.io 中测试代码,你会看到以下代码:

string a = "sdasd";
object b = (object)a;
object c = (object)a;
if (b is string mystring) {
Console.WriteLine(mystring);
}
if (c is string mystring1) {
Console.WriteLine(mystring1);
}

翻译过来就是这样:

string text = "sdasd";
object obj = text;
object obj2 = text;
string text2 = obj as string;
if (text2 != null)
{
Console.WriteLine(text2);
}
string text3 = obj2 as string;
if (text3 != null)
{
Console.WriteLine(text3);
}

最新更新