【发布时间】:2022-07-01 20:50:00
【问题描述】:
在 python 中,我已经养成了在“范围”之外的 for 循环中使用变量的习惯。例如:
l = ["one", "two", "three"]
for item in l:
if item == "one":
j = item
print(j)
你不能在 C# 中完全做到这一点。以下是我进行的几次尝试:
第一次尝试
我声明了一个string 类型的变量j,在foreach 循环范围内将所选项目分配给它,然后在我退出foreach 循环范围后重新引用它:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> l = new List<string> { "one", "two", "three" };
string j;
foreach (string item in l)
{
if (item == "one")
{
j = item;
}
}
Console.WriteLine(j);
}
}
编译器抛出错误:
Microsoft (R) Visual C# 编译器版本 4.2.0-4.22252.24 (47cdc16a) 版权所有 (C) 微软公司。保留所有权利。
test.cs(19,27): error CS0165: Use of unassigned local variable 'j'
第二次尝试
将声明移到foreach 内也不好,因为在作用域之外根本无法识别变量:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> l = new List<string> { "one", "two", "three" };
foreach (string item in l)
{
string j;
if (item == "one")
{
j = item;
}
}
Console.WriteLine(j);
}
}
编译器抛出以下错误:
Microsoft (R) Visual C# 编译器版本 4.2.0-4.22252.24 (47cdc16a) 版权所有 (C) 微软公司。保留所有权利。
test.cs(20,27): 错误 CS0103: 名称 'j' 在当前上下文中不存在
第三次尝试:
将声明移动到最内层范围并将值分配给变量会导致与第二次尝试类似的问题:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> l = new List<string> { "one", "two", "three" };
foreach (string item in l)
{
if (item == "one")
{
string j = item;
}
}
Console.WriteLine(j);
}
}
编译器报错,因为在第 19 行变量 j 无法识别。
Microsoft (R) Visual C# 编译器版本 4.2.0-4.22252.24 (47cdc16a) 版权所有 (C) 微软公司。保留所有权利。
test.cs(19,27): error CS0103: name 'j' does not exist in the current context
解决办法
一种可能的解决方案如下:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> l = new List<string> { "one", "two", "three" };
string j = "test";
foreach (string item in l)
{
if (item == "one")
{
j = item;
}
}
Console.WriteLine(j);
}
}
但我发现这很丑陋并且缺乏鲁棒性,因为我必须为j 分配一些虚拟值。例如,字符串 "test" 可能会被我的程序的其他部分识别,并使其以意想不到的方式运行。
问题
是否有一种优雅的替代方法可以在 C# 中实现这种行为,还是我遗漏了什么?
【问题讨论】:
-
第一次尝试更正确,但编译器告诉您,在某些情况下(您的集合为空),
j永远不会被分配给。您的解决方案即将完成,但我将使用j = null,而不是j="test,然后在您的foreach 之后,确保j 在使用之前不为空。 -
字符串 j="";也可以。使用空字符串 - 请参阅 stackoverflow.com/questions/263191/…
-
@Neil 这意味着我必须将我想以这种方式使用的任何变量声明为可为空(例如
string? j、int? j或char? j...对吗?在这种情况下,null和string.Empty有什么区别,有什么关系吗? -
第一次尝试:如果 l 为空(已初始化但没有项目),j 将永远不会被赋值。在这种情况下,您需要为其分配一个值。解决方案是在循环之前将其设置为一个值(null、空字符串或某个默认值)。然后编译器会很高兴。例如
string j = "";而不是string j;。 -
“我错过了什么吗?” - C# 语言中的许多设计决策会产生与 Java 和 C 等类似语言不同的结果,这是由于对这些模式可能导致错误的频率的经验。正如所暗示的那样,如果循环从未运行,则永远不会分配变量,并且(在其他语言中)可能是令人惊讶且难以追踪错误的来源。