1. 类的声明
类的声明格式如下:
attributes class-modifiers class identifier class-base class-body;其中attributes(属性集)、class-modifiers(类的修饰符)、class-base(继续方式)、class-body(基类名)。
类的修饰符:
l new:仅允许在嵌套类声明时使用,表明类中隐藏了由基类中继承而来的、与基类中同名的成员
l public:表示不限制对该类的访问
l protected:表示只能从所在类和所在类派生的子类进行访问
l internal:只有其所在类才能访问
l private:只有对包.Net中的应用程序或库才能访问
l abstract:抽象类,不允许对类进行实例化
l sealed:密封类,不允许被继承
需要注意的是,如果定义类时,如果类的修饰符被忽略的话,缺省为private。
2. 类的成员
类的成员可以分为两大类:
l 类本身所声明
l 从基类中继承而来
类的成员有以下类型:
l 成员常量
l 域:即类中的变量
l 成员方法
l 属性
l 事件
l 索引指示器:允许像使用数组那样为类添加路径列表
l 操作符:定义类中特有的操作
l 构造函数和析构函数:分别对类实例化和销毁
包含有可执行代码的成员被认为是类中的函数成员,这些函数成员有方法、属性、索引指示器、操作符、构造函数和析构函数
2.1. this保留字
保留字this仅限于在构造函数、类的方法、类的实例中使用,它有以下含义:
l 在类的构造函数中,this作为一个值类型,它表示对正在构造的对象本身的引用
l 在类的方法中出现的this作为一个值类型,它表示对调用方法的对象的引用
l 在结构的构造函数中出现的this作为一个变量类型,它表示对正在构造的结构的引用
l 在结构的方法中出现的this作为一个变量类型,它表示对调用该方法的结构的引用
2.2. 静态成员和非静态成员
静态成员是属于类,非静态成员是属于类的对象。类的非静态成员属于类的实例所有,每创建一个类的实例,都在内存中为非静态成员开辟一块区域,而类的静态成员属于类所有,为这个类的所在实例共享。无论这个类创建多少对象,一个静态成员在内存中只占有一块区域。
2.3. 成员常量
让我们看看一个成员常量的声明例子:
class Program { public const double X = 1.0; public const double Y = 2.0; public const double Z = 3.0; } |
类的常量可以加上以下修饰符:
l new
l public
l protected
l private
l internal
3. 构造函数和析构函数
3.1. 构造函数
构造函数用于执行类的实例化。每个类都在构造函数,即使我们没有声明它,编译器也会自动为我们提供一个默认的构造函数。在访问一个类的时候,系统将最先执行构造函数的语句。实际上,在任何构造函数的执行都隐式地调用了系统提供的默认的构造函数base()。
使用构造函数请注意以下几个问题:
l 一个类的构造函数通常与类名相同
l 构造函数不声明返回类型
l 一般地,构造函数总是public类型。如果是private类型的,表明类不能被实例化,这通常用于只含有静态成员的类
l 在构造函数中不要做对类的实例化以外的事情,也不要尝试显式地调用构造函数
3.2. 析构函数
C#中提供了析构函数,用于专门释放被占用的系统资源。
析构函数的名字与类名相同,只是在前面加了一个符号~。析构函数不接受任何参数,也不返回任何值。
析构函数不能是继承而来的,也不能显式地调用,C#提供了垃圾收集器可以完成回收资源。
4. 方法
4.1. 方法的声明
方法声明格式:atttributes method-modifiers return-type
member-name(formal-parameter-list) method-body,在方法声明中,至少应包括方法名称、修饰符和参数类型,返回值和参数名则不是必须的。
需要注意的是,方法名不应与同一个类中其它方法同名,也不能与类中的
其它成员名称相同。
方法的修饰符可以是:
l new
l public
l protected
l internal
l private
l static
l virtual
l sealed
l override
l abstract
l extern
对于使用了abstract和extern修饰符的方法,方法体仅仅只有一个简单
的分号。
C#在方法的执行部分通过return语句得到返回值。
4.2. 方法中的参数
C#中方法的参数有四种类型:
l 值参数,不含任何修饰符
l 引用型参数,以ref修饰符
l 输出参数,以out修饰符
l 数组型参数,以params修饰符声明
4.2.1. 值参数
当利用值参数向方法传递参数时,编译程序给实参的值做一份拷贝,并且将此拷贝传递给该方法。被调用的方法不会修改内存中实参的值,所以使用值参数时,可以保证值勤是安全的。
4.2.2. 引用型参数
和值参数不同的是,引用型参数并不开辟新的内存区域。当利用引用型参数向方法传递形参时,编译程序将把实际值在内存中的地址传递给方法。如:
class Program { static void Swap(ref int x,ref int y) { int temp=x; x=y; y = temp; } static void Main(string[] args) { int x=10,y=5; Swap(ref x, ref y); Console.WriteLine("x={0},y={1}",x,y); Console.ReadLine(); } }
运行结果: x=5,y=10 |
4.2.3. 输出参数
与引用型参数类似,输出型参数也不开辟新的内存区域。与引用型参数的类别在于,调用方法前无需对变量进行初始化。输出型参数用于传递方法返回的数据。如:
class Program { static void SplitPath(string path,out string dir,out string name) { int i = path.Length; while (i > 0) { char ch = path[i - 1]; if (ch == '//' || ch == '/' || ch == ':') break; i--; } dir = path.Substring(0,i); name = path.Substring(i); } static void Main(string[] args) { string dir, name; SplitPath("c://Windows//system//hello.txt",out dir ,out name); Console.WriteLine(dir); Console.WriteLine(name); Console.ReadLine(); }
运行结果: c:/Windows/system hello.txt |
4.2.4. 数组型参数
如果形参表中包含了数组型参数,那么它必须在参数表中位于最后。另外,参数中允许一维数组。比如,string[]和string[][]类型都可以作为数组型参数,而string[,]则不能。最后,数组型参数不能再有ref和out修饰符。如:
class Program { static void F(params int[] args) { Console.WriteLine("Array contains{0} elements:",args.Length); foreach (int i in args) Console.Write("{0}",i); Console.WriteLine(); } static void Main(string[] args) { int[] a = { 1,2,3}; F(a); F(10,20,30,40); F(); Console.ReadLine(); } } |
4.3. 静态和非静态方法
和静态和非静态属性一样,静态方法只属于类,非静态只能被类的对象调
用。静态方法只能访问类中静态成员,不能访问非静态成员;而非静态方法除了所有成员。
4.4. 方法重载
在一个类中有可能存在多个方法名相同的方法,当然也包括继承,就是方
法的重载。当调用这样的方法时,从以下几点区分:
l 参数个数
l 参数类型
l 参数顺序
4.5. 操作符重载
假如有两个类A、B,分别有两个开整型属性x、y,a、b分别是类A、B的对象,这时可以对x、y两个属性进行相加,a.x+b.y。这样的写法存在两个问题:
l 不够简洁,不够直观
l 如果不是使用public修饰符的话,这种访问是非法的
在这各情况下,C#定义了操作符重载。
在C#中,操作符重载总是在类中进行声明,并且通过调用类的成员方法来实现。操作符重载声明的格式为:type operator operator-name(formal-param-list),在C#中,下列操作符都是可以重载的:
+ - ! ~ ++ -- true false * / % & | ^ <<
>> == != > < >= <=
4.5.1. 一元操作符重载
一元操作符重载时操作符只作用于一个对象,此时参数为空,当前对象作为操作符的单操作数。
实例如下,游戏中扮演的角色有内力、体力、经验值、剩余体力、剩余内力五个属性,每当经验值达到一定程序时,角色便会升级,体力、内力上升,剩余体力和内力补满。这时可以通过重载操作符++来实现。如:
class Player { public int neili; public int tili; public int jingyan; public int neili_r; public int tili_r; public Player() { neili = 10; tili = 50; jingyan = 0; neili_r = 50; tili_r = 50; } public static Player operator ++(Player p) { p.neili = p.neili + 50; p.tili = p.tili + 100; p.neili_r = p.neili; p.tili_r = p.tili; return p; } public void Show() { Console.WriteLine("Tili:{0}",tili); Console.WriteLine("Jingyan:{0}",jingyan); Console.WriteLine("Neili:{0}",neili); Console.WriteLine("Tili_full:{0}",tili_r); Console.WriteLine("Neili_full:{0}",neili_r); } } class Program { static void Main(string[] args) { Player man = new Player(); man.Show(); man++; Console.WriteLine("Now upgrading......"); man.Show(); Console.ReadLine(); } } |
4.5.2. 二元操作符重载
大多数情况下我们使用二元操作符重载。这时参数中有一个参数,当前对象作为该操作符的左操作数,参数作为操作符的右操作数。如:
class DKR { public int x,y,z; public DKR(int x,int y,int z) { this.x = x; this.y = y; this.z = z; } public static DKR operator +(DKR d1,DKR d2) { DKR d = new DKR(0,0,0); d.x = d1.x + d2.x; d.y = d1.y + d2.y; d.z = d1.z + d1.z; return d; } } class Program { static void Main(string[] args) { DKR d1 = new DKR(3,2,1); DKR d2 = new DKR(0,6,5); DKR d3 = d1 + d2; Console.WriteLine("The 3d location of d3 is:{0},{1},{2}",d3.x,d3.y,d3.z); Console.ReadLine(); } } |