变量

在C#中声明变量使用下述语法:

datatype identifier;

例如:

int i;

该语句声明int变量i。编译器不会让我们使用这个变量,除非我们用一个值初始化了该变量。但这个声明会在堆栈中给它分配4个字节,以保存其值。

一旦它被声明之后,就可以使用赋值运算符(=)给它分配一个值:

i = 10;

还可以在一行代码中声明变量,并初始化它的值:

int i = 10;

其语法与C++和Java语法相同,但与VB中声明变量的语法完全不同。如果你是一位VB6用户,应记住C#不区分对象和简单的类型,所以不需要类似Set的关键字,即使是要把变量指向一个对象,也不需要Set关键字。无论变量的数据类型是什么,声明变量的C#语法都是相同的。

如果在一个语句中声明和初始化了多个变量,那么所有的变量都具有相同的数据类型:

int x = 10, y =20; // x and y are both ints

要声明类型不同的变量,需要使用单独的语句。在多个变量的声明中,不能指定不同的数据类型:

int x = 10;

bool y = true; // Creates a variable that stores true or false

int x = 10, bool y = true; // This won't compile!

2.3.1 变量的初始化
变量的初始化是C#强调安全性的另一个例子。简单地说,C#编译器需要用某个初始值对变量进行初始化,之后才能在操作中引用该变量。大多数现代编译器把没有初始化标记为警告,但C#编译器把它当作错误来看待。这就可以防止我们无意中从其他程序遗留下来的内存中获取垃圾值。

C#有两个方法可确保变量在使用前进行了初始化:

● 变量是类或结构中的字段,如果没有显式进行初始化,在默认状态下当创建这些变量时,其值就是0。

● 方法的局部变量必须在代码中显式初始化,之后才能在语句中使用它们的值。此时,初始化不是在声明该变量时进行的,但编译器会通过方法检查所有可能的路径,如果检测到局部变量在初始化之前就使用了它的值,就会产生错误。

C#的方法与C++的方法相反,在C++中,编译器让程序员确保变量在使用之前进行了初始化,在VB中,所有的变量都会自动把其值设置为0。

例如,在C#中不能使用下面的语句:

public static int Main()

{

int d;

Console.WriteLine(d); // Can't do this! Need to initialize d before use

return 0;

}

注意在这段代码中,演示了如何定义Main(),使之返回一个int类型的数据,而不是void的数据。

在编译这些代码时,会得到下面的错误消息:

Use of unassigned local variable 'd'

同样的规则也适用于引用类型。考虑下面的语句:

Something objSomething;

在C++中,上面的代码会在堆栈中创建Something类的一个实例。在C#中,这行代码仅会为Something对象创建一个引用,但这个引用还没有指向任何对象。对该变量调用方法或属性会导致错误。

在C#中实例化一个引用对象需要使用new关键字。如上所述,创建一个引用,使用new关键字把该引用指向存储在堆上的一个对象:

objSomething = new Something(); // This creates a Something on the heap

2.3.2 变量的作用域
变量的作用域是可以访问该变量的代码区域。一般情况下,确定作用域有以下规则:

● 只要字段所属的类在某个作用域内,其字段(也称为成员变量)也在该作用域内(在C++、Java和 VB中也是这样)。

● 局部变量存在于表示声明该变量的块语句或方法结束的封闭花括号之前的作用域内。

● 在for、while或类似语句中声明的局部变量存在于该循环体内(C++程序员注意,这与C++的ANSI标准相同。Microsoft C++编译器的早期版本不遵守该标准,但在循环停止后这种变量仍存在)。

1. 局部变量的作用域冲突
大型程序在不同部分为不同的变量使用相同的变量名是很常见的。只要变量的作用域是程序的不同部分,就不会有问题,也不会产生模糊性。但要注意,同名的局部变量不能在同一作用域内声明两次,所以不能使用下面的代码:

int x = 20;

// some more code

int x = 30;

考虑下面的代码示例:

using System;



namespace Wrox.ProCSharp.Basics

{

public class ScopeTest

{

public static int Main()

{

for (int i = 0; i < 10; i++)

{

Console.WriteLine(i);

} // i goes out of scope here



// We can declare a variable named i again, because

// there's no other variable with that name in scope

for (int i = 9; i >= 0; i--)

{

Console.WriteLine(i);

} // i goes out of scope here

return 0;

}

}

}

这段代码使用一个for循环打印出从0~9的数字,再打印从9~0的数字。重要的是在同一个方法中,代码中的变量i声明了两次。可以这么做的原因是在两次声明中,i都是在循环内部声明的,所以变量i对于循环来说是局部变量。



下面看看另一个例子:

public static int Main()

{

int j = 20;

for (int i = 0; i < 10; i++)

{

int j = 30; // Can't do this - j is still in scope

Console.WriteLine(j + i);

}

return 0;

}

如果试图编译它,就会产生如下错误:

ScopeTest.cs(12,14): error CS0136: A local variable named 'j' cannot be declared in this scope because it would give a different meaning to 'j', which is already used in a 'parent or current' scope to denote something else

(局部变量j不能在这个作用域内声明两次,因为这会给变量j赋予不同的含义,已用在'parent or current'作用域内的变量j表示其他内容)

其原因是:变量j是在for循环开始前定义的,在执行for循环时应处于其作用域内,在Main方法结束执行后,变量j才超出作用域,第二个j(不合法)则在循环的作用域内,该作用域嵌套在Main方法的作用域内。编译器无法区别这两个变量,所以不允许声明第二个变量。这也是与C++不同的地方,在C++中,允许隐藏变量。

2. 字段和局部变量的作用域冲突
在某些环境下,可以区分名称相同(尽管不是经过完全限定的名称)、作用域相同的两个标识符。此时编译器允许声明第二个变量。原因是C#使得变量之间有一个基本的区分,它把声明为类型级的变量看作是字段,而把在方法中声明的变量看作局部变量。

考虑下面的代码:

using System;



namespace Wrox.ProCSharp.Basics

{

class ScopeTest2

{

static int j = 20;



public static void Main()

{

int j = 30;

Console.WriteLine(j);

return;

}

}

}

即使在Main方法的作用域内声明了两个变量j,这段代码也会编译—— j被定义在类级(class level)上,在该类删除前是不会超出作用域的(在本例中,当Main方法中断时,程序结束)。此时,在Main方法中声明的新变量j隐藏了同名的类级变量,所以在运行这段代码时,会显示数字30。

但是,如果要引用类级变量,该怎么办?可以使用语法object.fieldname,在对象的外部引用类的字段或结构。在上面的例子中,我们访问静态方法中的一个静态字段(静态字段详见下一节),所以不能使用类的实例,只能使用类本身的名称:



public static void Main()

{

int j = 30;

Console.WriteLine(ScopeTest2.j);

}

...

如果要访问一个实例字段(该字段属于类的一个特定实例),就需要使用this关键字。this的作用与C++和Java中的this相同,与VB中的Me相同。

2.3.3 常量
在声明和初始化变量时,在变量的前面加上关键字const,就可以把该变量指定为一个常量。顾名思义,常量是其值在使用过程中不会发生变化的变量:

const int a = 100; // This value cannot be changed

VB和C++开发人员会非常熟悉常量。但C++开发人员应注意,C#不支持C++常量的所有细微的特性。在C++中,变量不仅可以声明为常量,而且根据声明,还可以有常量指针,指向常量的变量指针、常量方法(不改变包含对象的内容),方法的常量参数等。这些细微的特性在C#中都删除了,我们只能把局部变量和字段声明为常量。

常量具有如下特征:

● 常量必须在声明时初始化。指定了其值后,就不能再修改了。

● 常量的值必须能在编译时用于计算。因此,不能用从一个变量中提取的值来初始化常量。如果需要这么做,应使用只读字段(详见第3章)。

● 常量总是静态的。但注意,不必(实际上,是不允许)在常量声明中包含修饰符static。

● 在程序中使用常量至少有3个好处:

● 常量用易于理解的清楚的名称替代了“含义不明确的数字或字符串”,使程序更易于阅读。

● 常量使程序更易于修改。例如,在C#程序中有一个SalesTax常量,该常量的值为6%。如果以后销售税率发生变化,可以把新值赋给这个常量,就可以修改所有的税款计算,而不必查找整个程序,修改税率为0.06的每个项。



● 常量更容易避免程序出现错误。如果要把另一个值赋给程序中的一个常量,而该常量已经有了一个值,编译器就会报告错误。
posted @ 2009-05-09 00:07  yzhw.2008  阅读(492)  评论(0编辑  收藏  举报