首页 > 解决方案 > 不能在此范围内声明名为“student”的本​​地或参数,因为该名称在封闭的本地范围中用于定义本地参数

问题描述

我有一个C#程序如下

internal class Program
{
    private static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("Hello MongoDb!");
            MainAsync().Wait();
        }
        catch (Exception ex)
        {
            Console.WriteLine("Some Exception ", ex.Message);
        }
        }

    private static async Task MainAsync()
    {
        string con = "mongodb://localhost:27017";
        var client = new MongoClient(con);

        IMongoDatabase db = client.GetDatabase("School", new MongoDatabaseSettings());
        var collection = db.GetCollection<Student>("Students");
        using (IAsyncCursor<Student> cursor = await collection.FindAsync(filter, options))
        {
            while (cursor.MoveNext())
            {
                IEnumerable<Student> students = cursor.Current;
                foreach (var student in students) //line#1
                {
                    Console.WriteLine(student.Name);
                }
            }
        }

        var student = collection.Find(filter).FirstOrDefault(); //line#2
    }
}

现在我对 C# 变量和范围的了解是,在student第 1 行命名的变量(请参阅注释)是本地的并且仅在foreach范围内可用。

而第 2 行的变量 student 是不同的,并且有一个局部的MainAsync()方法范围。

此外,C# 没有像 javascript 这样的提升功能,因此在第 1 行,具有相同的变量已经可用。

那为什么我会收到以下错误。

不能在此范围内声明名为“student”的本​​地或参数,因为该名称在封闭的本地范围中用于定义本地参数

谢谢!

标签: c#

解决方案


那为什么我会收到以下错误。

无法在此范围内声明名为“student”的本​​地或参数,因为该名称在封闭的本地范围中用于定义本地参数

发生这种情况的原因是编译器在后台将您的代码翻译成执行的中间语言的方式。

为了更好地解释这一点,让我们创建一些简单的示例。

int[] students = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

foreach (int student in students)
{
    Console.WriteLine(student);
}

foreach (int student in students)
{
    Console.WriteLine(student);
}

当我们创建此代码时,编译器可以看到您只是在重用名称,这没有错,所以当它为您编译代码时(实际运行它)。它会为你做一些优化来帮助你。

编译器会生成类似这样的东西,这样它就可以跟踪相同的命名变量而不会引起问题,并对其进行优化,这样它就不必创建比它需要的更多的对象。

int[] students = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

int student;

int length = students.Length; // this wouldn't be named length, it would have a randomly generated un-callable name that can't be referenced.

for (int i = 0; i < length; i++)
{
    student = students[i];

    Console.WriteLine(student);
}

for (int i = 0; i < length; i++)
{
    student = students[i];

    Console.WriteLine(student);
}

这就是我们可以看到尝试创建具有相同名称的不同类型或具有相同名称的相同类型的另一个对象的问题

如果我们尝试创建具有不同类型的类似名称的变量,编译器将无法在运行时创建该变量,因为已经使用不同类型命名并创建了一个变量。

就拿这个例子来说,这里我们做的和之前一样,但是后面我们使用相同的名字。

int[] students = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

foreach (int student in students)
{
    Console.WriteLine(student);
}

foreach (int student in students)
{
    Console.WriteLine(student);
}

int[] student = students[0..2];

原因(在一般意义上)是因为编译器在稍后尝试将您的代码转换为以下内容时会遇到错误:

int[] students = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

int student;

int length = students.Length;

for (int i = 0; i < length; i++)
{
    student = students[i];

    Console.WriteLine(student);
}

for (int i = 0; i < length; i++)
{
    student = students[i];

    Console.WriteLine(student);
}

// compiler can't create a variable with the same name again, 
// especially with a different type!!
int[] student = new int[2];

student[0] = students[0];
student[1] = students[1];

如果我们尝试创建相同的类型和相同的名称,也会发生同样的事情。编译器会遇到污染具有相同名称的方法变量的问题。

让我们看看它可能是什么样子

int[] students = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

int student = 12;

foreach (int student in students)
{
    Console.WriteLine(student);
}

foreach (int student in students)
{
    Console.WriteLine(student);
}

会被翻译成这样的:

int[] students = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

int student;

// compiler can't create a second copy of student
int student = 12;

int length = students.Length;

for (int i = 0; i < length; i++)
{
    student = students[i];

    Console.WriteLine(student);
}

for (int i = 0; i < length; i++)
{
    student = students[i];

    Console.WriteLine(student);
}

编者注
以上是对高级主题的过度概括,编写示例是为了最好地说明为什么会发生这种情况,同时也避免使使用真实 IL 传达的信息过于复杂。编译器通常不会生成 IL 任何看起来像我提供的东西。


推荐阅读