C#面向对象概念总结

来源:互联网 发布:淘宝怎么清仓 编辑:程序博客网 时间:2024/05/22 09:04
面向对象的最基本的特征是封装性、继承性和多态性:
1. 封装
封装就是指把对象的全部属性和全部服务结合在一起形成一个不可分割的独立单位。
封装是一种信息隐蔽技术,用户只能见到对象封装界面上的信息,对象内部对用户是隐蔽的。
封装的目的在于将对象的使用者与设计者分开,使用者不必了解对象行为的具体实现,只需要用设计者提供的消息接口来访问该对象。
例如,各种有标准视频接口的设备都可以连接电视机。 

2.继承
特殊类的对象拥有其一般类的全部属性与服务,称作特殊类对一般类的继承,即在特殊类中不必重新定义已在一般类中定义过的属性和服务,这种特性在面向对象中称作对象的继承性。
继承在C#中称为派生,其中,一般类称为基类或父类,特殊类称为派生类或子类。
例如灵长类动物称为一般类,具有属性包括手和脚(其它动物没有),具有的服务是抓取东西(其它动物没有),人类作为特殊的灵长类高级动物,除了继承灵长类动物的所有属性和服务外,还具有特殊的服务(创造工具)。
继承机制的优势在于降低了软件开发的复杂性和费用,使软件系统易于扩充 

3.  多态
多态性是指在基类中定义的属性或服务被派生类继承后,可以具有不同的数据类型或表现出不同的行为。
为了实现多态性,需要在派生类中更改从基类中自动继承来的数据类型或方法。
这种为了替换基类的部分内容而在派生类中重新进行定义的操作,在面向对象概念中称之为覆盖。
例如,假设机动车类是一个基类,它具有一个称为更换轮胎的方法,但是当从机动车派生火车类时,火车更话车轮的方法与一般的机动车不同,于是只能通过覆盖的方法在火车类中重新定义一个更换车轮的方法,以替换其基类的方法。
多态性的优势在于使软件开发更加方便,增加程序的可读性。
类的常量成员是一种符号常量,必须指定名称和值
访问修饰符包括:public、private、internal、protected、protected internal。
       在使用访问修饰符来定义命名空间、结构和类及其成员
时,需注意:
(1)一个成员或类型只能有一个访问修饰符,使用protected internal组合时除外。
(2)命名空间上不允许使用访问修饰符,命名空间没有访问限制。
(3)如果未指定访问修饰符,则使用默认的可访问性,类成员默认为private。
(4)顶级类型(不嵌套在其他类型中的类型)的可访问性只能是internal或public,默认可访问性是internal。
定义方法的详细说明
(1) 访问修饰符控制方法的访问级别,可用于方法的修饰符包括:public、protected、private、internal等等。
(2) 方法的返回值类型可以是任何合法的数据类型,包括值类型和引用类型。当无返回值时,返回值类型使用void关键字来表示。
(3) 方法名必须符合C#的命名规范,与变量名命名规则相同。
(4) 参数列表是方法可以接受的输入数据。当方法不需要参数时,可省略参数列表,但不能省略圆括号。当参数不止一个时,需要使用逗号作间隔,同时每一个参数都必须声明数据类型,即使这些参数的数据类型相同也不例外。
(5) 花括号{}中的内容为方法的主体,由若干条语句组成,每一条语句都必须使用分号结尾。当方法结束时如果需要返回操作结果,则使用return语句返回,此时要注意return语句返回的值的类型要与方法返回值类型相匹配。如果方法使用void标记为无返回值的方法,可省略return语句。 

1. 值类型参数
调用方向方法传递值类型参数时,调用方将把实参变量的值赋给相对应的形参变量,即实参变量和形参变量是两个不相同的变量。
实参变量的值传递给形参变量时是一种单向值传递。 
引用型参数
与值参数不同,调用方向方法传递引用类型参数时,调用方将把实参变量的引用赋给相对应的形参变量。实参变量的引用代表数据值的内存地址,因此,形参变量和实参变量将指向同一个引用。
如果在方法内部更改了形参变量所引用的数据值,则同时也修改了实参变量所引用的数据值。
由于使用return语句一次只能返回一个数据,如果需要返回多个数据,则可以利用引用型参数的这个特点来实现。
C#通过ref关键字来声明引用参数,无论是形参还是实参,只要希望传递数据的引用,就必须添加ref关键字。
输出参数
方法中的return语句只能返回一个运算结果,虽然也可以使用引用型参数返回计算结果,但要求先初始化实参。
而输出参数不需要对实参进行初始化,它专门用于把方法中的数据通过形参返回给实参,但不会将实参的值传递给形参。一个方法中可允许有多个输出参数。
C#通过out关键字来声明输出参数,无论是形参还是实参,只要是输出参数,都必须添加out关键字。 
数组型参数
把数组作为参数,有两种使用形式:
一种是在形参数组前不添加params修饰符
另一种是在形参数组前添加params修饰符。
两种形式的区别
不添加params修饰符时,所对应的实参必须是一个数组名。
添加params修饰符时,所对应的实参可以是数组名,也可以是数组元素值的列表。
值得注意的是,无论采用哪一种形式,形参数组都不能定义数组长度。
方法的重载 
方法的重载是指在同一个类型中,以同样的名称声明两个或多个方法。当需要以不同的参数列表执行同样的操作时,方法重载将会很有用。 

2. 析构函数的特点:
(1) 不能在结构中定义析构函数,只能对类使用析构函数;
(2) 一个类只能有一个析构函数;
(3) 无法继承或重载析构函数;
(4) 析构函数既没有修饰符,也没有参数;
(5) 在析构函数被调用时,.Net Framework的CLR自动添加对基类Object.Finalize方法的调用以清理现场,因此在析构函数中不能包含对Object.Finalize方法的调用。 

注意,在默认情况下,编译器自动生成空的析构函数,因此C#不允许定义空的析构函数 

1. 静态类的定义:
静态类使用static关键字来声明,表明它仅包含静态成员。
不能使用new关键字创建静态类的实例 。
在实际应用中,当类中的成员不与特定对象关联的时候,就可以把它创建为静态类。

2. 静态类的主要功能:
(1) 静态类仅包含静态成员;
(2) 静态类不能被实例化;
(3) 静态类是密封的;
(4) 静态类不能包含实例构造函数。

3. 静态类的优点:
(1) 编译器能够自动执行检查,以确保不添加实例成员;
(2) 静态类能够使程序的实现更简单、迅速,因为不必创建对象就能调用其方法。 
注意:因为静态类是密封的,因此不可被继承。另外,静态类不能包含实例构造函数,但仍可以声明静态构造函数,以分配初始值或设置某个静态状态。 
(1) 派生类的特点
可以拥有自己的成员。
可以隐式地从基类继承所有成员,包括方法、字段、属性和事件,但私有成员、构造函数和析构函数等除外。
派生类只能从一个类中继承 
密封类
使用密封类可以阻止一个类的代码被其他类继承
使用密封类的好处:
可以提高应用程序的可靠性和性能(在.NET Framework公共语言运行时CLR中,加载密封类时将对密封类的方法调用进行优化)。
软件企业通过使用密封类还可以把自己的知识产权保护起来,避免他人共享代码。
在C#中,添加关键字sealed可以声明密封类。 

4.为了使用派生类能更改基类的数据和行为,C#提供了两种选择:1.使用新的派生类成员替换基成员2.   重写虚拟的基成员  
使用virtual和override时要注意以下几点:
(1)字段不能是虚拟的,只有方法、属性、事件和索引器才可以是虚拟的;
(2)使用virtual修饰符后,不允许再使用static、abstract或override修饰符;
(3)派生类对象即使被强制转换为基类对象,所引用的仍然是派生类的成员;
(4)派生类可以通过密封来停止虚拟继承,此时派生类的成员使用sealed override声明。

抽象类的特点:
抽象类是用来作为基类的,不能直接实例化,而且只能使用abstract关键字来标识。抽象类的用途是提供多个派生类可共享的基类的公共定义。
抽象类可以包含抽象的成员,如抽象属性和抽象方法,也可以包含非抽象的成员,甚至还可以包含虚方法。
抽象属性的特点
类的属性成员添加了abstract关键字后,就成了抽象属性。
抽象属性声明不提供属性访问器的实现,它只声明该类支持的属性,而将访问器的实现留给派生类。
抽象属性同样可以是只读的、只写的或可读写的属性。
当派生类从抽象类中继承一个抽象属性时,派生类必须重载该抽象属性。
抽象属性使用abstract关键字来标识 

抽象方法的特点:
类的方法成员添加abstract关键字后,就成为抽象方法。
抽象方法声明不提供方法的实现,它必须是一个空方法,而将方法实现留给派生类。
当派生类从抽象类中继承一个抽象方法时,派生类必须重载该抽象方法。
由于抽象方法没有实现,因此,抽象方法不包含常规的方法体,以分号结尾。


1.委托(delegate)是一种引用方法的类型,它与类、接口和数组相同,属于引用型。

在C#程序中,可以声明委托类型、定义委托类型的变量、把方法分配给委托变量,还可以通过委托来间接地调用一个或多个方法。
一旦为委托分配了方法,委托将与该方法具有完全相同的行为。
C#允许把任何具有相同签名(相同的返回值和参数)的方法分配给委托变量。
委托的实质是代表方法的引用(即内存地址),是定义回调方法的理想选择,也是C#实现事件驱动的编程模型的主要途径。 
委托具有以下特点:
(1)委托类似于 C++ 函数指针,是完全面向对象的,是安全的数据类型。
(2)委托允许将方法作为参数进行传递。
(3)委托可用于定义回调方法。
(4)委托可以链接在一起。例如,可以对一个事件调用多个方法。
(5)委托签名不需要与方法精确匹配。 


集合是通过高度结构化的方式存储任意对象的类,与无法动态调整大小的数组相比,集合不仅能随意调整大小,而且对存储或检索存储在其中的对象提供了更高级的方法。

集合可以把一组类似的类型化对象组合在一起。
选择集合类时,一般要考虑以下问题:
(1)是否需要一个序列列表,需要先进先出行为时可使用 Queue 队列类,在需要后进先出行为时可使用 Stack栈类。
(2)是否需要随机访问集合中的元素,此时不能选择Queue 队列类、Stack栈类、LinkedList 双向链表类。
(3)是否需要通过索引访问每个元素,只有ArrayList动态数组类、StringCollection字符串集合类等是从索引为零的元素开始逐个访问集合元素。Hashtable哈希表、Dictionary字典类通过元素的键(即元素名字)提供对元素的访问。而NameValueCollection 类和SortedList 泛型类通过其元素的从零开始的索引,或者通过其元素的键提供对元素的访问。
(4)是否包含一个值、一个键和一个值的集合,还是一个键和多个值的集合。其中,“一个值”的集合是一种基于 IList 列表接口派生的集合,“一个键和一个值”的集合是一种基于IDictionary字典接口的集合,“一个键和多个值”的集合是 NameValueCollection 类。
(5)是否需要用与输入元素方式不同的方式对元素排序。Hashtable 哈希表类按其元素的哈希代码对元素排序,SortedList有序表类以及 SortedDictionary有序字典根据 IComparer 可比较接口来实现按键对元素的排序,而ArrayList动态数组类提供 Sort 排序方法。
(6)是否需要信息的快速搜索和检索,对于小集合(10个元素或更少),ListDictionary 比 Hashtable 快,SortedDictionary 泛型类提供比 Dictionary 泛型类更快的查找。
(7)是否需要只接受字符串的集合,如使用StringCollection和 StringDictionary等。


动态数组类ArrayList不限制元素的个数和数据类型。

(1)  ArrayList与Array的区别
Array 的大小是固定的,而 ArrayList的大小可根据需要自动扩充;
在Array中一次只能获取或设置一个元素的值,而在ArrayList中允许添加、插入或移除某一范围的元素;
Array 的下限可以自定义,而ArrayList的下限始终为零;
Array 可以具有多个维度,而 ArrayList始终只是一维的;
Array 位于 System 命名空间中,ArrayList 位于 System.Collections 命名空间中。
(2) 创建动态数组:
ArrayList  列表对象名 = new ArrayList(?);


队列的特点

一种先进先出的数据结构,当插入或删除对象时,对象从队列的一端插入,从另外一端移除 
创建队列对象 
Queue 队列名 =  new Queue([队列长度][,增长因子]);
说明,队列长度默认为32,增长因子默认为2.0(即每当队列容量不足时,队列长度调整为原来的2倍)
注意,由于调整队列的大小需要付出一定的性能代价,因此建议在构造队列时指定队列的长度。
常用队列操作方法包括Enqueue向队尾添加数据、Dequeue移除队头数据、Peek返回队头数据、Clear清空队列和Contains检查是否包含某个数据等。其中,Enqueue和Dequeue每操作一次只能添加或删除一个数据。


栈的特点:

一种先进后出的数据结构,这种数据结构在插入或删除对象时,只能在栈顶插入或删除。 
创建栈对象:
Stack 栈名 =  new Stack(?);
栈常用方法包括Push在栈顶添加数据、Pop移除栈顶数据、Peek返回栈顶数据、Clear清空栈和Contain检查是否包含某个数据等。其中,Push和Pop每操作一次只能添加或删除一个数据。


哈希表又称散列表,表示键/值对的集合。

哈希表的特点:在保存集合元素时,首先要根据键自动计算哈希代码,以确定该元素的保存位置,再把元素的值放入相应位置所指向的存储桶中。查找时,再次通过键所对应的哈希代码到特定存储桶中搜索。这样可以大大减少为查找一个元素进行的比较次数。
创建哈希表对象
Hashtable 哈希表名 =  new Hashtable([哈希表长度][,增长因子]);
说明,默认长度为0,默认增长因子为1.0
哈希表常用操作方法包括Add添加数据、Remove移除数据、Clear清空哈希表和Contains检查是否包含某个数据等。其中, Add方法需要两个参数,一个是键,一个是值;Remove方法只需要一个键名参数。 


接口索引器与类索引器的区别有两个:

一是接口索引器不使用修饰符;
二是接口索引器只包含访问器get或set,没有实现语句。


创建自定义的泛型类时,需要特别注意以下事项:

(1)将哪些类型通用化为类型参数
一般规则是:能够参数化的类型越多,代码就会变得越灵活,重用性就越好,但太多的通用化会使其他开发人员难以阅读或理解代码。
(2)如果存在约束,应对类型参数应用什么约束
一般规则是:应用尽可能最多的约束,但仍能够处理需要处理的类型。例如,如果知道泛型类仅用于引用类型,则应用类约束。这可以防止泛型类被意外地用于值类型。 
(3)是否将泛型行为分解为基类和子类
由于泛型类可以作为基类使用,其注意事项与非泛型类相同。
(4)是否实现一个或多个泛型接口。 


事件处理系统的构成要素

(1) 事件源:指能触发事件的对象,有时又称为事件的发送者或事件的发布者;
(2) 侦听器:指能接收到事件消息的对象,Windows提供了基础的事件侦听服务;
(3) 事件处理程序:当事件发生时对事件进行处理,又称事件函数或事件方法,包含事件处理程序的对象称为事件的接收者,又称事件的订阅者。 


C#中的事件具有以下特点:

(1) 事件是类用来通知对象需要执行某种操作的方式;
(2) 尽管事件在其他时候(如信号状态更改)也很有用,但通常还是用在图形用户界面中;
(3) 事件通常使用委托事件处理程序进行声明;
(4) 事件可以调用匿名方法来替代委托。
1. 事件的基本概念
触发事件的对象称为发布者,提供事件处理程序的对象称为订阅者。在.NET Framework中,基于事件驱动的程序使用委托来绑定事件和事件函数,在C#中,事件实际上就是一个委托类型的变量。
C#允许使用内置的EventHandler委托类型来声明一个标准的事件,也允许先自定义委托,再声明自定义事件。
在.NET Framework中,内置的EventHandler委托具有两个参数,它们的数据类型分别是Object和EventArgs类型,并且没有返回值。
Object参数名通常为sender,表示事件发布者本身;EventArgs参数通常为e,它将System.EventArgs类的新实例传递给事件函数。在实际编程中,有时需要从EventArgs类派生自定义事件参数类,这样发布者可以将特定的数据发送给接收者的事件函数。
事件的声明
(1) 使用内置的EventHandler委托声明事件的形式(标准事件)
格式:public event EventHandler 事件名;
     其中,事件名通常使用on作为前缀符。
例如,public event EventHandler onClick;
(2) 使用自定义的委托类型声明事件
格式:public delegate 返回值类型 委托类型名([参数]);
                public event 委托类型名 事件名;
其中,委托类型的参数非常灵活,可以省略,可以是标准的Object参数和EventArgs参数,也可以是其他参数,但一定要注意保证与事件函数的参数匹配。
在订阅事件时要把握好以下几点:
(1)首先接收类必须具有与事件自身具有相同签名(相同返回值类型和参数)的方法,然后该方法(称为事件处理程序)可以采取适当的操作来响应该事件。
(2) 每个事件可有多个处理程序,多个处理程序按顺序调用。如果一个处理程序引发异常,还未调用的处理程序则没有机会接收事件。基于这个原因,建议事件处理程序迅速处理事件并避免引发异常。
(3) 若要订阅事件,接收器必须创建一个与事件具有相同类型的委托,并使用事件处理程序作为委托目标,还要使用加法赋值运算符 (+=) 将该委托添加到源对象的事件中。
(4) 若要取消订阅事件,接收器可以使用减法赋值运算符(?=)从源对象的事件中移除事件处理程序的委托。
0 0
原创粉丝点击