在其内部使用变量在其外部进行循环范围。在python中可能是可能的,但在C#中不可能
在Python中,我已经养成了在A内部在其“范围”之外使用变量的习惯。例如:
l = ["one", "two", "three"]
for item in l:
if item == "one":
j = item
print(j)
您不能完全在C#中这样做。这是我进行的几次尝试:
第一次尝试,
我声明了一个变量 j
type 字符串
,将所选项目分配给 foreach
loop loop范围,然后在我退出 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.22222.24(47CDC16A) 版权(C)Microsoft Corporation。保留所有权利。
test.cs(19,27):错误CS0165:使用未分配的本地变量'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.22222.24(47CDC16A) 版权(C)Microsoft Corporation。保留所有权利。
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.22222.24(47CDC16A) 版权(C)Microsoft Corporation。保留所有权利。
test.cs(19,27):错误cs0103:当前上下文中不存在名称'j'
。解决方案
一个可能的解决方案如下:
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#中实现这种行为,还是我错过了什么?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
首先尝试更正确,但是编译器告诉您,在某些情况下(您的收藏为空),J将永远不会分配给。您的解决方案快到了,但是我将使用
j =“ test”
,而是使用j = null
,然后在您的foreach之后,请确保在使用之前使用j不是null它First attempt is more correct, but the compiler is telling you that in certain cases (where your collection is empty), j will never be assigned to. Your solution is nearly there, but instead of
j="test"
, I would usej = null
, and then after your foreach, make sure j is not null before using it完全不要写循环。您对列表中应发生的元素的期望是什么?sup> 1 ?从您的样本中看来,它应该至少一次,但可能完全是一次。
然后选择适当的表达您的期望清楚地表达了:
如果一个元素完全不符合我们的标准,则以上会引发异常。您可以选择
第一个
或最后一个
(或带有ordeffault
)变体以表达您的要求和期望。1 或换句话说,如果列表为空或列表中没有元素与您的搜索条件匹配您的期望是什么?
您的Python代码似乎只是假设两个都不是真实的。 C#旨在帮助您发现诸如此类摇摇欲坠的假设即将发挥作用的地方,并防止您以这种假设编写代码。
从历史上看,未分配的变量一直是很难追踪错误的巨大来源,因为它们要么包含垃圾(通常但并非总是很快就会引起错误)或默认值(在相当长的一段时间内看起来像是真正的价值),症状在与破裂的假设完全不同的位置出现。
Don't write the loop at all. What is your expectation for how often an element in your list should occur1? From your sample, it appears it should be at least once, but maybe exactly once.
Then pick the appropriate LINQ method that expresses your expectations clearly:
The above will throw an exception if exactly one element doesn't match our criteria. You may instead pick
First
orLast
(or withOrDefault
) variants to express your requirements and expectations.1 Or to put it another way, what is your expectations if the list is empty or no elements in the list match your search criteria?
Your python code appears to continue just assuming that neither of those are true. C# was designed to help you spot where shaky assumptions such as this are coming into play and prevent you from writing code with such assumptions.
Unassigned variables have, historically, been a massive source of hard to track down bugs because they either contain garbage (often but not always provoking an error quite soon) or a default value (which may look like a genuine value for quite some time), with the symptoms arising in a completely different location to the broken assumption.
也许修复此操作的更高的方法是初始化这样的变量:
Maybe a little more sofisticated way to fix this is to initialize the variable like this:
您并不是真正使用循环中的每个值,而是要获得匹配的最后一个值。作为替代方案,您可以使用linq,然后查询列表并提供默认值:例如:
使用第一个示例可以设置或检查默认值的null
You are not really using each of the values in the loop but just get the LAST one that matches. As an alternative you could use Linq and then query your list and supply a default value for example:
Using your first example you can set or check for a null for a default