面向对象程序设计在处理对象时,必须遵循三个原则:封装、继承和多态。
(一)、类的成员
类的成员主要包括数据成员和方法成员,类是完成对它们封装的结构类型。类的数据成员可以是常量、字段和对象。方法成员包含方法、属性、索引器、事件、操作符、构造函数、析构函数等。当字段、方法、属性、事件、运算符、和构造函数声明中含有static修饰符时,则表明它们是静态成员,否则是实例成员。静态成员属于类,而实例成员属于对象。
类成员声明时,可以使用以下5种访问修饰符中的一种:public、protected、internal、private、protected internal。当类成员声明中不包含访问修饰符时,默认访问修饰符为private。
1、常量声明,语法形式:[修饰符]const 类型 常量名 = 常量表达式;其中,修饰符:new、public、protected、internal、private。const是关键字,是声明常量必需的符号。类型,可以是值类型和引用类型,但结构不能是常量。
注:常量在声明的同时必须初始化,所以常量表达式必须是能够在编译时计算确定的值。常量是隐式的静态成员,不能用static修饰,但它属于类而不属于对象,因此使用常量时需要用“类名.常量名”来引用。
2、字段声明(字段也称为域),语法形式:[修饰符]类型 变量声明列表;其中,修饰符:new、public、protected、interal、private、static、readonly。若字段用readonly修饰符声明,则表示该字段为只读字段。只读字段只能在字段定义中及字段所属类的实例构造函数或静态构造函数中进行赋值,在其他情况下均不能改变只读字段的值。
(二)、构造函数
如果类中没有定义构造函数,系统会执行Object提供的默认构造函数。构造函数的函数名必须和类名一样。不带参数的构造函数称为“默认构造函数”。无论何时,只要使用new实例化对象,并且不为new提供任何参数,就会调用默认构造函数。除非类是static的,否则C#编译器将为无构造函数的类提供一个公共的默认构造函数。
1、实例构造函数,初始化对象。
2、静态构造函数,初始化类。被static修饰符修饰,没有参数。一个类只能有一个静态构造函数。
3、私有构造函数,通常用在只包含静态成员的类中。如果类具有一个或多个私有构造函数而没有公共构造函数,则不允许创建该类的实例。注:如果不对构造函数使用访问修饰符,则在默认情况下为私有构造函数。
构造函数的重载,函数重载是一个类中声明了多个同名的构造函数,但有不同的参数个数和参数类型,或者参数个数和参数类型相同,但是参数的排列顺序不同。
(三)、方法中的参数传递
1、传递值类型的参数,使用“值传递”的方法来传递参数。当方法被调用时,便会为方法中每个值类型分配一个新的内存空间,然后把实参值复制一份传给对应的形参,存储在为它分配的内存空间中。形参接受了实参的值后与实参不再存有任何联系。在方法中对形参的修改不会影响到对应的实参,这种传递方式又称为单向传递。
class Program { static void exch(int a, int b)//定义方法 { int t; t = a; a = b; b = t; } public static void Main() { int x, y; Console.WriteLine("请输入x和y的值:"); x = Convert.ToInt32(Console.ReadLine()); y = Convert.ToInt32(Console.ReadLine()); exch(x,y); Console.WriteLine("转化后的x和y的值:{0},{1}", x, y); Console.ReadKey(); } }
2、传递引用类型的参数,使用“引用传递”的方法来传递参数。传递引用类型参数是向方法传递实参在内存中的地址。在C#中要通过引用方式传递数据,需使用关键字ref。使用方法是在定义方法时,在按引用传递的形式参数的类型说明符前加上关键字ref,在调用方法时,在按引用传递的实际参数之前加上关键字ref。
class Program { static void exch(ref int a,ref int b)//定义方法,引用类型参数 { int t; t = a; a = b; b = t; } public static void Main() { int x, y; Console.WriteLine("请输入x和y的值:"); x = Convert.ToInt32(Console.ReadLine()); y = Convert.ToInt32(Console.ReadLine()); exch(ref x,ref y); Console.WriteLine("转化后的x和y的值:{0},{1}", x, y); Console.ReadKey(); } }
3、传递多个引用类型参数,完成这种数据传递方式所使用的是输出型参数,用关键字out表示。与引用型参数的区别是:调用方法前无须对变量进行初始化,因此,在out参数没有被显式地赋值之前,不能使用。
public class Calculate { public void Cal(int inNum, out int outNum1, out int outNum2) { outNum1 = inNum * inNum; outNum2 = inNum * 10; } } class Test { public static void Main() { Calculate cal = new Calculate(); int outnum1;//不必初始化 int outnum2;//不必初始化 cal.Cal(35, out outnum1, out outnum2); Console.WriteLine("outnum1:{0}", outnum1); Console.WriteLine("outnum2:{0}", outnum2); Console.ReadKey(); } }
4、传递个数不确定的参数,C#采用参数数组,形参数组前如果用params修饰符进行声明就是参数数组,通过参数数组可以向函数传递个数变化的参数。若形参表中含一个参数数组,则该参数数组必须位于形参列表的最后。参数数组必须是一维数组。不允许将params修饰符与ref和out修饰符组合起来使用。与参数数组对应的实参可以是同一类型的数组名,也可以是任意多个与该数组的元素属于同一类型的变量。若实参是数组则按引用传递,若实参是变量或表达式则按值传递。
class ParamsTest { static int ParamsMeth(ref int sum, params int[] arr) { int i; for (i = 0; i < arr.Length; i++) { sum = sum + arr[i]; arr[i] = arr[i] * arr[i]; } return (arr[arr.Length - 1]); } static void Main() { int[] a = { 1, 2, 3 }; int i,L; int s = 0, z = 0; ParamsMeth(ref s, a);//数组作为实参 Console.WriteLine("数组作为实参的结果:"); Console.WriteLine("和为:{0}",s); for (i = 0; i < a.Length; i++) Console.WriteLine("a[{0}]={1}",i,a[i]); Console.WriteLine("与形参数组的元素属于同一类型的变量做实参的结果:"); L = ParamsMeth(ref z, 23, 45);//与形参数组的元素属于同一类型的变量做实参 Console.WriteLine("和为:{0}",z); Console.WriteLine("输入最后数值的乘积:{0}",L); Console.ReadKey(); } }
(四)、实例方法和静态方法
定义静态方法时用static修饰符,定义一个静态方法时,不能用virtual、abstract或override修饰符。静态方法属于类所有,实例方法属于类定义的对象所有。实例方法可以访问类中包括静态成员在内的所有成员,而静态方法只能访问类中的静态成员。
class Program { static string string1="这是一个静态数据成员"; int n=5; static void print(string str)//静态方法 { Console.WriteLine(str); Console.WriteLine(string1);//调用静态成员string1 //在静态方法中调用非静态成员n,错误 //Console.WriteLine(n); } void myprint(string str)//实例方法 { print(str);//在实例方法中调用静态成员的print方法,正确 Console.WriteLine("非静态成员n的值:{0}", n);//调用非静态成员 } static void Main(string[] args) { Program test = new Program(); test.myprint("调用实例方法"); Program.print("调用静态方法");//这样是正确的 Console.ReadKey(); } }
(五)、属性和索引器
属性的定义类似于方法的定义,属性的使用类似于字段的使用。属性完善了C#的封装功能,使得所有的数据成员都可以成为私有成员。
1、属性的声明和使用,属性分为两部分组成:属性头和存取器。存取器分为get访问器和set访问器。属性声明的语法形式:[修饰符]类型说明符 属性名{访问声明},其中,修饰符:new、public、protected、internal、private、static、virtual、override和abstract 9种。访问声明用来声明属性访问器。给属性赋值时使用set访问器,获取属性值时使用get访问器。set访问器带有一个特殊的关键字value,value是set访问器的隐式参数,在set中通过value将外部的输入传递进来,然后赋值给类中的某个变量成员。get访问器是一个不带参数的方法,用于向外部返回属性成员的值。通常访问函数的语句或语句块主要由return或throw语句返回某个变量成员的值。属性可以是实例成员,也可以是属于整个类的静态成员。
public class Employee { //定义三个私有字段 private string name; private long ID; private int salary; public Employee(string n, long i, int s)//构造函数 { name = n; ID = i; salary = s; } public string Name//声明属性Name,实现外部对私有字段name的访问 { get { return name; } set { if (name != value) name = value; } } public int Salary//声明属性Salary,实现外部对私有字段salary的访问 { get { return salary; } set { salary = value; } } public long GetID//声明属性GetID,实现对私有字段ID的外部访问 { get { return ID; } set { ID = value; } } public void EmployeeInfo() { Console.WriteLine("Name:{0}",name); Console.WriteLine("ID number:{0}",ID); Console.WriteLine("Salary:{0}",salary); } } public class App { public static void Main() { Employee myEmployee1=new Employee("smith",05060023,3600); myEmployee1.EmployeeInfo(); Employee myEmployee2=new Employee("",0,0); //利用属性Name、GetID、Salary给私有变量name、ID、salary赋值 myEmployee2.Name = "John"; myEmployee2.GetID = 05060012; myEmployee2.Salary = 3500; myEmployee2.EmployeeInfo(); Console.ReadKey(); } }
2、索引器的声明和使用,索引器允许按照与数组相同的方式对类、结构或接口进行索引。索引器声明的语法形式:[修饰符]索引器声明符{访问器声明},其中,修饰符:可以是new、virtual、sealed、override、abstract、extern以及public、protected、internal、private 4个访问修饰符的有效组合。注意,索引器修饰符不可以是static的。索引器声明符的形式有两种,分别是:类型 this [形参表] 或 类型 接口类型 this [形参表],注意,这里的“[]”不表示可选,是索引器声明符的必要部分。而this是C#中的关键字,除了可以声明索引器以外,还用于限定被相似的名称隐藏的成员、将对象作为参数传递到其他方法。使用索引器的形式为:对象名.[实参]。索引器只能是实例成员,属于某一个具体的对象。
class Student { private string[] name; public Student() { name = new string[] { "Robot", "Jack", "Lily", "Rose", "Smith", "Lindon" }; } public string this[int index]//声明索引器,实现对数组name的访问 { get { return name[index]; } set { name[index] = value; } } public int GetNameLength() { return name.Length; } } public class StudentApp { public static void Main() { Student stu = new Student(); for (int i = 0; i < stu.GetNameLength(); i++) Console.WriteLine("{0}",stu[i]);//使用索引器访问数组name //更改name中倒数第二个元素值 Console.WriteLine("更改元素值后:"); stu[stu.GetNameLength() - 2] = "Green"; for (int i = 0; i < stu.GetNameLength(); i++) Console.WriteLine("{0}", stu[i]); Console.ReadKey(); } }
学习来源:《Visual C#.NET实用教程》清华大学出版社 主编:师硕、于明。学习资料:C#语言基础.rar
发表评论: