在其内部使用变量在其外部进行循环范围。在python中可能是可能的,但在C#中不可能

发布于 2025-02-12 03:58:36 字数 3014 浏览 2 评论 0 原文

在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#中实现这种行为,还是我错过了什么?

In python, I've gotten into the habit of using variables inside a for loop outside of its "scope". For example:

l = ["one", "two", "three"]

for item in l:
    if item == "one":
        j = item

print(j)

You can't quite do this in C#. Here are the several attempts I made:

First attempt

I declare a variable j of type string, assign the selected item to it inside the foreach loop scope and then refer back to it once I exit the foreach loop scope:

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);
    }
}

The compiler throws an error:

Microsoft (R) Visual C# Compiler version 4.2.0-4.22252.24 (47cdc16a)
Copyright (C) Microsoft Corporation. All rights reserved.

test.cs(19,27): error CS0165: Use of unassigned local variable 'j'

Second attempt

Moving the declaration inside the foreach is also no good, because the variable is not recognized outside of the scope at all:

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);
    }
}

The compiler throws the following error:

Microsoft (R) Visual C# Compiler version 4.2.0-4.22252.24 (47cdc16a)
Copyright (C) Microsoft Corporation. All rights reserved.

test.cs(20,27): error CS0103: The name 'j' does not exist in the current context

Third attempt:

Moving the declaration in the innermost scope and assigning the value to the variable results in a similar problem as the second attempt:

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);
    }
}

The compiler complains because at line 19 the variable j is not recognized.

Microsoft (R) Visual C# Compiler version 4.2.0-4.22252.24 (47cdc16a)
Copyright (C) Microsoft Corporation. All rights reserved.

test.cs(19,27): error CS0103: The name 'j' does not exist in the current context

The solution

One possible solution is as follows:

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);
    }
}

But I find this to be quite ugly and lacking robustness, because I have to assign some dummy value to j. For instance, perhaps the string "test" is recognized by other parts of my program and would make it behave in unexpected ways.

Question

Is there an elegant alternative to achieve this kind of behavior in C#, or am I missing something?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

安静 2025-02-19 03:58:36

首先尝试更正确,但是编译器告诉您,在某些情况下(您的收藏为空),J将永远不会分配给。您的解决方案快到了,但是我将使用 j =“ test” ,而是使用 j = null ,然后在您的foreach之后,请确保在使用之前使用j不是null它

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<string> l = new List<string> { "one", "two", "three" };
        string j = null;

        foreach (string item in l)
        {

            if (item == "one")
            {
                j = item;
            }
        }

        if(j!=null) <-- check j has been assigned to, before using it.
        {
            Console.WriteLine(j);
        }
        else
        {
            Console.WriteLine("Item was not found");
        }
    }
}

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 use j = null, and then after your foreach, make sure j is not null before using it

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<string> l = new List<string> { "one", "two", "three" };
        string j = null;

        foreach (string item in l)
        {

            if (item == "one")
            {
                j = item;
            }
        }

        if(j!=null) <-- check j has been assigned to, before using it.
        {
            Console.WriteLine(j);
        }
        else
        {
            Console.WriteLine("Item was not found");
        }
    }
}
请爱~陌生人 2025-02-19 03:58:36

完全不要写循环。您对列表中应发生的元素的期望是什么?sup> 1 ?从您的样本中看来,它应该至少一次,但可能完全是一次。

然后选择适当的表达您的期望清楚地表达了:

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        List<string> l = new List<string> { "one", "two", "three" };
        string j = l.Single(item=>item=="one");       

        Console.WriteLine(j);
    }
}

如果一个元素完全不符合我们的标准,则以上会引发异常。您可以选择第一个最后一个(或带有 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:

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        List<string> l = new List<string> { "one", "two", "three" };
        string j = l.Single(item=>item=="one");       

        Console.WriteLine(j);
    }
}

The above will throw an exception if exactly one element doesn't match our criteria. You may instead pick First or Last (or with OrDefault) 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.

北凤男飞 2025-02-19 03:58:36

也许修复此操作的更高的方法是初始化这样的变量:

string j = string.Empty;

Maybe a little more sofisticated way to fix this is to initialize the variable like this:

string j = string.Empty;
梦中楼上月下 2025-02-19 03:58:36

您并不是真正使用循环中的每个值,而是要获得匹配的最后一个值。作为替代方案,您可以使用linq,然后查询列表并提供默认值:例如:

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        List<string> myList = new List<string>{"one", "two", "three"};
        string defaultValue = "whateverwant";
        string matchMe = "one";
        string j = myList.Where(item => item == matchMe)
            .DefaultIfEmpty(defaultValue)
            .Select(item => item).FirstOrDefault();
        Console.WriteLine(j);
    }
}

使用第一个示例可以设置或检查默认值的null

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<string> l = new List<string> { "one", "two", "three" };
        string j = null;// or a default value string so we avoid the ternary

        foreach (string item in l)
        {
            if (item == "one")
            {
                j = item;
                break; // we found one so no need to keep looping
            }
        }

        j = string.IsNullOrEmpty(j)?"default":j
        Console.WriteLine(j);
    }
}

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 System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        List<string> myList = new List<string>{"one", "two", "three"};
        string defaultValue = "whateverwant";
        string matchMe = "one";
        string j = myList.Where(item => item == matchMe)
            .DefaultIfEmpty(defaultValue)
            .Select(item => item).FirstOrDefault();
        Console.WriteLine(j);
    }
}

Using your first example you can set or check for a null for a default

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<string> l = new List<string> { "one", "two", "three" };
        string j = null;// or a default value string so we avoid the ternary

        foreach (string item in l)
        {
            if (item == "one")
            {
                j = item;
                break; // we found one so no need to keep looping
            }
        }

        j = string.IsNullOrEmpty(j)?"default":j
        Console.WriteLine(j);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文