了解局部变量的作用域
介绍
当在 C# 程序的方法中声明变量时,其范围是预定义的,并且其可见性在程序的其余部分中也是定义的。当以这种方式创建变量时,只要其方法正在执行,该变量就可用。但是,当控制权传递给另一个方法时,其范围就会结束。这种类型的变量称为局部变量。
在本指南中,我们将了解局部变量的范围并解决与 C# 代码中变量声明的位置相关的问题。
局部变量的示例:
using System;
public class NewProgram {
public static void Main(string[] args) {
int x;
x = 10; // local variable
Console.WriteLine("Value:" + x);
}
}
输出将是:
Value:10
这些变量只能在该函数内部的代码块中使用。
还有其他方法可以定义和使用变量,即在类中声明它(或将其声明为全局变量),这使得该类中的所有方法都可以使用它。
可以从类或命名空间中的任何位置访问全局变量。C# 不直接支持全局变量,但可以通过创建静态类来实现全局变量的功能,这在特定情况下很有用。作为一般做法,最好避免使用全局变量,因为它们违反了 C# 面向对象的编程理念,并且在多线程等情况下会使事情变得复杂。请小心避免冲突,方法是添加锁或确保在任何给定实例中只有一个线程可以访问全局变量。
变量的作用域位于其声明的完整代码块内。此外,由于代码块有时会根据应用程序要求进行嵌套,因此在类的方法中定义的循环会提供三个嵌套代码块,从而提供三层嵌套作用域。如果变量在任何这些作用域中定义,它将对当前作用域和嵌套在其中的作用域可见。
简单来说:
- 在循环内声明的变量在循环外不可见。
- 在循环外声明的变量也可以在循环内部访问。
C# 中的变量范围
为了更好地理解局部变量的作用域,理解 C# 中的作用域级别非常重要。
类级作用域
类中定义的变量可供类中声明的所有非静态方法使用,这些方法称为字段或类成员。它们的访问修饰符不会影响它们在类内的作用域,并且可以使用访问修饰符在类外部访问它们。
例如:
using System;
class ClassScope { // class level scope starts here
int abc = 1000; // class level variable with class level scope
public void display() {
Console.WriteLine(a); // method to access the class level variable
} // method ends here
} // class level scope ends
方法级作用域
方法内声明的变量可供其相应部分以及嵌套代码块使用。它们在方法之外不可用。这些是局部变量。方法执行完成后,变量将不复存在。
static void Main(string[] args) {
int marks; // Declared at the method-level
marks = 100; // Used at the method-level
if (marks >= 50)
Console.WriteLine("Great Marks are : {0}", marks); // Used in the nested scope
else
Console.WriteLine("Bad marks are : {0}", marks); // Again, used in the nested scope
}
输出将是:
Great Marks are : 100
嵌套作用域
我们之前已经解释过,在嵌套作用域中声明的变量在其各自的代码块之外不可用。这些可以称为循环变量。我们将在下面的例子中展示,在if语句的嵌套作用域中声明的变量不能在方法级别使用,并且不会编译。
static void Main(string [] args){
int score = 100;
if (score >= 60)
string message = "Good score"; // Declared in if statement
else
string message = "Poor score"; // Declared in else statement
Console.WriteLine(message); // Variable unavailable
}
输出将是:
Error(s):
(15:9) Embedded statement cannot be a declaration or labeled statement
(17:6) Embedded statement cannot be a declaration or labeled statement
如果我们想让这段代码正常工作,我们可以在if语句之前声明变量,并在if语句内为其分配一个值。
*注意:C 和 C# 中的范围定义之间存在关键差异。
如果 C# 变量在块 (if/else) 的局部范围内定义,并且与该块之后定义的变量相冲突,则会出现错误。在 C/C++ 或 Java 下编译的代码类似。局部变量将在整个声明它们的块中保持作用域。这与 C++ 相反,在 C++ 中,局部变量只有在声明后才在其块中的某个点处于作用域中。
public void function(){
if (true) {
/* scope of local if */
int a = 2;
System.Console.WriteLine(a);
} else {
/* no conflict arises with same if/else */
int a = 4;
System.Console.WriteLine(a);
}
if (true) {
/* no conflict with local from different if scope */
int a = 10;
System.Console.WriteLine(a);
}
}
我们知道,在声明一个作用域时,外部作用域中的任何局部变量都是已知的。作用域内的局部变量不可能覆盖外部作用域的局部变量。
范围和相关错误消息
C# 的一般经验规则是:
- 局部变量声明和嵌套局部变量声明空间包含同名元素是错误的。
- 如果在局部变量的范围内,该变量位于局部变量声明符之前的文本位置,则会发生编译时错误。 如果局部变量声明是隐式的,则在其局部变量声明符中引用该变量仍会出现错误。
通过一个简单的例子就可以理解和记住这些规则。
class Clarity {
public int time;
void Function() {
int seconds;
seconds = 0; // (Line 1) Will bind to local variable defined above
time = 0; // (Line 2) Binds to field time
{
seconds = "s"; // (Line 3) Will bind to local variable defined below
string seconds;
time = "s"; // (Line 4) Binds to local variable defined below.
string time;
}
}
}
在第 2 行,人们会认为seconds会像第 1 行一样绑定到Clarity.seconds。但是,C# 规范明确定义该名称将解析到最接近的范围。在第 3 行和第 4 行将出现编译器错误。
但是,允许引用声明器内的局部变量,尽管它不是隐式类型的。因此,以下情况将成立:
int a = (x = 5); // Allowed
var b = (y = 10); // Will result in an error
在第一个语句中,我们已经将类型声明为int。绑定时,这是可以的,因为左侧(变量初始化器)是合适的。同时,我们最初没有b的类型,因此绑定时,我们不确定是否可以将 10 分配给b。
可以做的一件事是隐藏名称。这只允许在当前范围中未被引用的字段上使用。我们可以将变量重新定义为字符串,因为它在给定方法的范围中尚未被引用。
我们意识到这种在声明符前使用名称的方法会导致编译器产生错误,这并不理想。简单来说,普通名称将解析为当前块内声明的任何语句,而不管块外是否存在同名变量或定义。
此外,在 2005 C# 编译器中,我们错误地将 s 的两个语句绑定到外部局部变量,而第 1 行可以完美绑定。但第 2 行出现错误,报告字符串无法转换为int。第 3 行也出现错误,报告您无法将s重新声明为其他内容。
然后,在 2008 C# 编译器中,这个问题得到了修复,以正确反映规范。第 1 行和第 2 行都将绑定到第 3 行。由于它们在文本上位于声明之前,因此两者都会产生错误,表明它们在声明之前被使用。第 3 行还会出现一个错误,提示您无法重新声明s。
结论
本指南解释了 C# 中局部变量的作用域。有了这些知识,我们可以避免常见的绑定问题和错误,并在正确的范围内定义变量。如果变量中出现未知错误或垃圾值,可以在了解范围后通过分配值来解决。
快乐学习 C#!
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~