




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、在.NET中,继承按照其分类方式不同,一般分类如下:实现继承:派生类继承了积累的所有属性和方法,并且只能有一个积累,在.NET中System.Object是所有类型的最终基类,这种继承方式称为实现继承。接口继承:派生类继承了接口的方法签名。不同于实现继承的是,接口继承允许多继承,同时派生类只继承了方法签名而没有方法实现,具体的实现必须在派生类中完成。因此,确切的说,这种继承方法应该称为接口实现。继承本质的认识继承是可传递的,子类是对父类的扩展,必须继承父类的方法,同时可以添加新方法。子类可以调用父类方法和字段,而父类不能调用子类的方法和字段。虚方法如果实现覆写操作,使得父类指针可以指向子类对象
2、成员。子类不光继承弗雷德公有成员,同时继承了父类的私有成员,只是在子类中不被访问。New关键字在虚方法继承中的阻断作用。关注对象原则:调用子类还是父类的方法,取决于创建的对象是子类对象还是父类对象,而不是它的引用类型。例如Bird bird2=new Chicken()时,我们关注的是其创建对象为Chicken类型,因此子类将继承父类的字段和方法,或者覆写父类的方法,而不是关注bird2的引用类型是否为Bird。引用类型的区别决定了不同的对象在方法中的不同的访问权限Bird bird=new Chicken();Chicken chicken=new Chicken();Bird对象和chic
3、ken对象在内存布局上是一样的,差别在于引用指针的类型不同,前者是Bird指针类型后者是Chicken指针类型 执行就近原则:对于同名字段或方法,编译器是按照其顺序查找来引用的,也就是访问离它创建最近的字段或方法。这是父类排在子类前,先于子类编译的原因。抽象类继承与接口继承在规则上的归纳抽象类适合于有族层概念的关系,而接口最适合不同类提供通用功能。接口着重于CAN-DO关系类型,而抽象类则偏重于IS-A是关系。接口多定义对象的行为;抽象类多定义对象的属性。如果预计会出现版本问题,可以创建抽象类因为值类型是密封的,所以只能实现接口,而不能继承类。继承之毒瘤主要体现在:继承可能造成子类的无限膨胀,
4、不利于类体系的安全和维护继承的子类对象确定于编译期,无法满足需要运行期才确定的情况,而类聚合很好地解决了这一问题随着继承层次的复杂化或者子类的多样化,不可避免的灰出现对父类的无效继承或者有害继承。子类部分的继承父类的方法或者属性,更能适应实际的设计需求面向对象的基本原则:多聚合,少继承,低耦合,高内聚Adapter模式就其实现方式主要包括:类的Adapter模式。通过引入新的类型来继承原有类型,同时实现新加入的接口方法。其缺点就是耦合度高,需要引入过多的新类型对象的Adapter模式。通过聚合而非继承的方式来实现对原有系统的扩展,松散耦合,较少的新类型继承中重点内容重点规则:密封类不可以被继承
5、继承关系中,我们跟多的是关注其共性而不是其特性,因为共性是层次复用的基础,而特性是系统扩展实现单继承,接口多继承从宏观来看,继承多关注与共通性,而多态则着眼于差异性继承的层次应该有所控制,否则类型之间的关系维护会消耗更多精力面向对象原则:多组合,少继承,低耦合,高内聚只读字段在构造函数中被赋值属性的实质是在编译时分别将get和set访问器实现对外方法,从而达到控制属性目的而对属性的读写伴随的实际是一个相应方法的调用,它以一种简单的方式实现了方法。get负责可读属性,set负责可写属性封装规则:尽可能的调用类的访问器,而不是成员,即使在类的内部内部私有部分可任意更改,但一定要在保证外部接口稳定的
6、前提下将对字段的读写控制实现为属性,而不是方法,否则舍近求远,非明智之选类封装是由设置访问权限来实现的,对内实现为private,对外实现为public。还要对protected,internal有较深的理解基类继承式多态:Flies myFile=new WORDFile();myFile.Open();/WORDFile为Files的子类接口实现式多态:IFliesOpen myFile=new WORDFile();myFile.Open();/IFliesOpen为接口通常将子类中共有的但却容易变化的特征抽取为虚函数在父类中定义,而在子类中通过覆写来实现操作多态的规则和意义:多态提供了
7、对同一类对象的差异化处理方式,实现了对变化和共性的有效封装和继承,体现了“一个接口,多种方法的”的思想,是方法抽象机制成为可能在.NET中,默认情况下方法是非虚的,以C#为例必须显式的通过virtual和abstract标记为虚方法或者抽象方法,以便在子类中覆写父类方法在面向对象的基本要素中,多态和继承、多态和重载存在紧密的联系,多态的基础就是建立有效的继承体系,一次继承和重载是多态的实现基础接口规则:接口隔离原则强调接口应该被实现为单一功能的小接口,而不要实现为具有多个功能的胖接口,类对于类的依赖应建立在最小的接口之上接口支持多继承,既可以作用于值类型,也可以作用于引用类型禁止为已发布的接口
8、添加新的成员,这意味着你必须重新修改所有实现了该接口的类型,在实际应用中,这往往是不可的事情接口不能被实例化,没有构造函数,接口的成员被隐式声明为public单一职责原则核心思想:一个类,最好只做一件事情,只有一个能引起它变化的原因单一职责原则建议:一个类只有一个引起它变的原因,否则就应考虑重构SRP(单一职责原则)又引起变化的原因决定,而不由功能职责决定。虽然职责常常是引起变化设为轴线,但有时未必测试驱动开发,有助于实现合理分离功能的设计可以通过Facade模式或Proxy模式进行职责分离开放封闭原则核心思想:软件实体应该是可扩展的,而不可修改的。也就是说,对扩展时开放的,而对修改是封闭的开
9、放封闭原则建议:开放封闭原则是最重要的设计原则,Liskov替换原则和合成/聚合复用原则为开放封闭原则的实现提供保证可以通过Template Method模式和Strategy模式惊喜重构,实现对修改封闭、对扩展开放的设计思路封装变化,是实现开放封闭原则的重要手段,对于经常发生变化的状态一般将其封装为一个抽象,例如银行业务中的IBankProcess接口拒绝滥用抽象,只讲经常变化的部分进行抽象,这种经验可以从设计模式的学习与应用中获得依赖倒置原则核心思想:依赖于抽象高层模块不应该依赖于底层模块,二者都应该依赖于抽象抽象不应该依赖于具体,集体应该依赖于抽象依赖倒置原则建议:抽象的稳定性决定了系统
10、的稳定性,因为抽象是保持不变的,依赖于抽象是面向对象设计的精髓,也是依赖倒置原则的核心思想依赖于抽象是一个通用规则,而某些时候依赖于于细节则是在所难免的,必须权衡再抽向和具体之间的取舍,方法是一成不变的依赖于抽闲,就是要对接口编程,不要对实现编程接口隔离原则核心思想:使用多个小的专门的接口,而不是使用一个大的总接口接口英爱是内聚的,应该避免出现“胖”接口一个类对另一个类的依赖应该建立在最小的接口上,不要强迫依赖不用的方法,这是一种接口污染分离的主要手段:委托分离,通过增加一个新的类型来委托客户的请求,隔离客户接口的未知依赖,但是会增加系统开销多重继承分离,通过接口多继承来实现客户需求,这种方式
11、值得推荐接口隔离原则建议:功能先进的接口合并,可能造成污染,实现内聚的接口才是接口设计的基本原则接口隔离原则,能够保证系统扩展和修改的硬性不会扩张到系统的其他部分,一定程度上保证了对开放封闭原则的遵守Liskov替换原则核心思想:子类必须能够替换基类Liskov替换原则实现方法:将公共部分抽象为基类的接口或抽象类,通过Extract Abstract Class,在子类中通过覆写父类的方法实现以新的方式支持同样职责Liskov替换原则建议:Liskov替换原则是关于继承机制的设计原则,违反了Liskov原则就必然导致违反开放封闭原则Liskov替换缓则能够保证系统具有良好的扩展性,同时实现基于
12、多态的抽象机制,能够见少代码冗余,避免运行期的类型判别子类必须满足基类和客户端对其的行为约定,客户端对行为的期望在基类和子类必须保持一致IS-A是基于行为凡是的,它依赖于客户端的调用方式,对象的行为方式才是值得关注的要素子类的一场必须控制在父类可预计的范围,否则将导致替换违规,违反了Liskov替换原则软件开发原则:面向抽象编程高耦合,低内聚封装变化实现重用:代码重用、算法重用为了达到高耦合低内聚目标:尽可能实现单项依赖不需要进行数据交换的双方,不哟啊实现多此一举的关联保持内部的封装性,关联的双方不要深入实现细节通信程序中的所有依赖关系都应终止于抽象类或接口依赖倒置设计要求:少继承,多聚合单向
13、依赖封装抽象对依赖关系都应终止于抽象类或接口任何变量都不应该持有一个指向据提类的指针或者引用任何类都不应该从具体类派生任何方法都不应该覆写它的任何基类中已经实现的方法系统架构应该有清晰的层次定义,层次之间接口箱外提供内聚服务,正如在三层架构中的示例一样典型的以new进行的对象创建操作,是对依赖倒置原则的典型违反,而通过依赖注入进行对象的创建解耦是常用的解决之道对抽象编程,需要增加必要的类和辅助代码进行支持, 某种程度上增加了系统的复杂度和维护成本当具体类不在变化时,遵守依赖倒置式多此一举模式的起点工厂方法(Factory Method Pattern)模式起点:将程序中创建对象的操作进行单独地
14、处理,大大提高了系统扩展的柔性,接口的抽象化处理给相互依赖的对象创建提供了最好的抽象模式典型应用:工厂方法模式是最简单也最容易理解的模式之一。其关注的核心是对于创建对象这件事的分离单例(Singleton Pattern)模式起点:一个类只有一个实例,且提供一个访问全局点的方式,更加灵活的保证了实例的粗行间和访问约束,并且唯一约束的实施由类本身实现典型应用:一个类只有一个实例,经常被用于Façade模式,称为单例外观命令(Command Pattern)模式起点:将请求封装为对象,从而将命令的执行责任分开。通常在列队中等待命令,这和现实多么相似啊。如果你喜欢发号施令,请考虑IComm
15、and典型应用:菜单系统策略(Stategy Pattern)模式起点:策略模式,将易于变化的部分封装为接口,通常Stategy封装一些运算法则,使之能相互交换典型应用:数据层常考虑以策略提供算法和数据的分离迭代器(Iterator Pattern)模式起点:相信任何的系统中,都会用到数组、集合、链表、队列这样的类型吧,那你就不得不关心迭代模式的来龙去脉。在遍历算法中,迭代模式提供了遍历的顺序访问容器,GOF给出的定义为:提供一种方法访问容器(Container)对象中各个元素,而又无需暴露该对象的内部细节典型应用:.NET中就是应用率迭代器来创建用于foreach的集合模板方法(Templa
16、te Method Pattern)模式起点:顾名思义,模板方法就是在副类中定义模板,然后又子类实现。具体的实现一般由父类定义算法的骨架,然后将算法的某些步骤委托给子类典型应用:ASP.NET的Page类观察者(Observer Pattern)模式起点:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。观察者和被观察者的分开,为模块划分提供了清晰的界限典型应用:在.NET中使用委托和事件可以更好地实现观察者模式,事件的注册和撤销不就对应着观察者对其对象的观察吗?职责链(Chain of Responsibility Pattern)模式起
17、点:将操作组成一个链表,通过遍历操作链表找到合适的处理器。通过统一的接口,被多个处理器实现,每个处理器都有后继处理器,可以将请求沿着处理器传递典型应用:GUI系统的事件传播桥接(Bridge Pattern)模式起点:把实现和逻辑分开,对于我们深刻理解面向对象聚合复用的思想甚至有助益典型应用:多版本.NET Framework通过环境变量与对应版本应用建立桥梁代理(Proxy Pattern)模式起点:将负载的逻辑封装起来,将代理对象控制实际对象的创建和访问,由代理对象屏蔽原有逻辑的复杂性典型应用:WCF服务代理装饰器(Decorator Pattern)模式起点:为原有系统,动态的增加或者删
18、除状态和行为,在继承被装饰类的同时包含被类装饰的实例成员典型应用:.NET中的Stream设计门面(Façade Pattern)模式起点:将表现层和逻辑层隔离,封装底层的复杂处理,为用户提供简单的接口,这样的例子随处可见。门面模式很多时候是一种系统架构设计,在很多项目中,都实现了门面模式的接口,为复杂系统的解耦提供了最好的解决方案典型应用:WSDL就是一个典型平台无关的门面应用组合(Composite Pattern)模式起点:不管是个体还是组件,都包含公共的操作接口,通过同样的方式来处理一个组合中的所有对象。组件的典型操作包括:增加、删除、查找、分组和获取子元素等典型应用:树形结
19、构的的数据组织适配器(Adapter Pattern)模式起点:在原类型不做任何改变的情况下,扩展新的接口,灵活且多样的适配一起旧俗。这种打破旧框框、适配新格局的思想,低是面向对象的精髓。以继承方式实现类的Adapter模式和以聚合方式实现对象的Adapter模式,各有千秋。看来把他们叫做包装器一点也不为过典型应用:RCW(Runtime Callable Wrapper)在COM Iterop中的应用模式建议:不要拿着GOF的书从头看到尾,对我们来说那是圣经也是字典,系统的学习其实意义不大软件设计中体会设计模式,设计就是不断有需求生成的重构结合.NET Framework框架来学习设计模式在
20、.NET中的应用,对了解设计模式来说是一举两得的是,既体味了设计,又深谙了框架重构、不断地重构切勿因模式而模式,任何的模式套用都意味着实现的复杂升级和执行的性能损耗面向对象与基于对象二者概念主要体现在:继承是区别面向对象与基于对象的核心所在,对于少了继承性的基于对象来说,自然就的好了多态性支持封装是面向对象与基于兑现的共同特征闭包的非必要条件:嵌套定义的函数匿名函数将函数作为参数或者返回值MANIFEST清单分析.assembly指令用于定义编译目标或加载外部库.ctor表示构造函数.ver表示引用版本.publickeytoken表示应用程序实际公钥标记.hash algorithm表示实现
21、安全性的哈希算法系统缺省值为0x00008004.moulde为程序指令集,表明定义模块的的元数据,以指定当前模块Imagebase为影响基地址.file alignment 为文件对其数值.subsystem为连接系统类型,0x0003表示从控制台运行.corflags 为实质运行库头文件标志,默认值1类分析.class表明是一个类auto表明程序加载时内存的布局是有CLR决定的,而不是其本身ansi属性则为了在没有托干和被托管代码之间实现无缝转换beforefiledinit属性为类提供了一个附加信息,用于标记运行库可以在任何时候执行构造函数方法,只要该方法在第一次被访问其静态之间执行即可
22、.ctor方法Cil managed说明方法体中为IL代码,指示编译器编译为托管代码.maxstack表明执行构造函数,ctor期间的评估堆栈可容纳数据项的最大个数IL_0000是一个标记代码的开头,一般来说,IL_标记之前的部分为变量的声明和初始化Ldarg.0表示装在第一个成员参数,在实例方法中指的是当前实例的引用,该引用将用于在基类构造函数中调用call调用静态方法和构造方法,callvirt调用实例方法Main方法.entrypoint指令表明了CLR加载程序时,是首先从,entrypoint方法开始执行的Ldst表示字符压栈hidebysig属性表示如果当前类作为父类时,类中的方法不
23、会被子类继承IL语言IL是一种面向对象的机器语言,因此具有面向对象语言的所有特性。;类、对象、继承、多态等仍然是IL语言的基本概念IL之零零独立于CPU指令,CLR通过JIT编译机制将其转换为本地代码IL和元数据是了解CLR运行机制的重要内容 Initobj构造新的值类型,完成值类型初始化;完成设定对指定的存储单元的指针指控newobj在初始化过程中会调用构造函数newarr用来创建一组从零其实的数组string类型的创建由ldstr指令来完成call用于执行静态调度,而callvirt用于执行动态调度 通用类型系统规则:.NET中,所有类型都继承中System.Object类可以给类型创建别
24、名,例如using mynet=A.MyClass一个对象的获取办法是:obj.GetType()Typeof操作符则常在反射时,回去自定义类的Type对象,从而可以获取该类型的方法、属性等可以使用CLSCompliantAttribute将程序集、模块、类型和成员标记为符合CLS或不符合CLSIL中使用/checked+开关来进行基元类型的溢出检查,在C#中实现这一功能的是checked和unchecked操作符命名空间时长功能角度对类型的划分,是一组类型在逻辑上的机集合值类型和引用类型内存分配值类型实例总是分配在它声明的地方,声明为局部变量时其被分配在堆栈上,声明为引用类型成员时其被分配在
25、托管堆上;引用类型的实例总是被分配在托管堆上 值类型 继承自ValueType(注意System.ValueType继承自System.Object);而引用类型继承自System.Object值类型包含其实例数据,每个变量保存率其本身的数据拷贝在默认情况下值类型的参数传递不会影响参数本身;而引用类型变量保存了其数据的引用地址,因此以按值方式进行参数传递会影响参数本身,因为两个变量会引用内存中的同一块地址典型值类型为:struct、enum以及大量内置值类型;能称为类的可以说是引用类型值类型的内存不由GC来控制,作用域结束时,值类型会自动释放,减少托管压力,因此具有性能上的优势值类型是密封的,
26、因此不能作为其他任何类型的基类,但是可以但集成或者多继承接口;引用类型一般都有几次性值类型不具有多态性;而引用类型有多态性值类型不可为null值,值类型都会自动初始化为0值;引用类型变量默认情况下,创建为null值,表示没有指向任何托管堆地址值类型有两种状态:装箱和未装箱,运行库提供了所有值类型的已装箱形式;而引用类型通常只有一种形式:装箱值类型应用场合数据较小的场合,最好考虑以值类型来实现系统性能的改善结构简单,不必在多态的情况下类型的性质不表现出行为时,不必以类来实现,那么以存取数据为主要目的的情况下,值类型是优先考虑的参数传递时,值类型默认情况下传递的是实例数据,而不是内存地址,因此数据
27、传递情况下的选择,取决于函数内部的实现逻辑。值类型可以有高效的内存支持,并且在不暴露内部结构的情况下返回实例的副本,从安全上考虑值类型,但过多的值类型传递也会损伤性能的优化值类型没有继承性,如果类型的选择,没有子类继承的必要,优先考虑值类型在有可能引起装箱与拆箱操作的集合或者队列中,值类型不是很好的选择,因为会引起对值类型的装箱操作,导致额外内存的分配例如频繁调用Hashtable对象的Add方法时将产生大量的装箱操作引用类型应用的场合可以简单的的说,引用类型是.NET世界的职业杀手,. NET世界就是由引用类型构成的,类是面向对象的基本概念,也是程序框架的基本要素,因此灵活的的护具封装特性使
28、得引用类型成为主流引用类型适用于结构复杂、有继承性、有多态、突出行为的场合参数传递情况也是需要考虑的情况解析Main(string args),Main函数的参数可以为空,也可以是string数组,其作用是接受命令行参数,例如在命令行运行程序时,args提供了输入命令行参数入口Params用法Param修士的必须为一堆数组,事实上通常就是以群的方式来实现或多个或者任意多个参数的控制的,而数组是最简单的选择param是修饰的参数数组,可以是任何类型。因此,如果需要接受任何类型的参数时,只要设置数组类型为object即可params必须在参数列表的最后的一个,并且只能使用一次ref和out不同点r
29、ef 要求传递之前的参数必须首先显示初始化,而out不需要。也就是说,使用ref的参数必须是一个实际的对象,而不能指向null;而使用out的参数可以接受指向null的对象然后再调用方法的内部必须完成对象的实体化装箱就是值类型数据转换为无类型的引对象拆箱就是引用类型转换为值类型装箱与拆箱雷区装箱的概念与拆箱的概念不是完全对等的互逆操作,从内存角度上来看,拆箱的性能开销远小于装箱,只是在实际的执行中,拆箱之后常常伴随着字段的拷贝,以C#而言,编译器总会自动产生拆箱后的字段拷贝只有被装过象的对象才能被拆箱,而并非所有的引用类型。将并非装箱而来的引用类型强制转换为值类型,将抛出InvalidCasE
30、xception装箱过程解析内存分配:在托管堆中分配内存空间,内存的大小为预装值类型的大小加上其他额外的内存空间,主要包括方法表指针和SyncBlockIndex,这两个成员用于CLR管理引用类型对象实例拷贝:将值类型的字段拷贝到新分配的内存中地址返回:将托管堆中的对象地址返回给新的引用类型拆箱过程解析实例检查:首先检查是否为null,如果是则抛出NullReferenceException异常;如果不是检查对象实例,确保它是给定类型的装箱值,并保证拆箱后的类型为原来的同一类型,否则会抛出InvalidCasException异常提示:在代码中,要显式 的判断装箱后的引用类型的原始类型。可以用
31、以下几种方法来判断Is操作符法if(o is Int32)Console.WriteLine(“Its Int32 type”);GetType法Console.WriteLine(o.GetType();指针返回:返回已经装箱对象中属于原值类型部分字段的地址。而附加成员:方法指针域SyncBlockIndex对该指针是不可见的装箱与拆箱的规则类型一致,拆箱必须保证执行后的结果是原来装箱时的类型,否则将抛出InvalidCasException异常装箱与拆箱主要是针对值类型而言的,引用类型总是以装箱形式存在的装箱和拆箱分为显式转换和隐式转换两种情况,在实际的编码中应该警惕隐式转换带来的性能与异
32、常 CLR管理内存的区域主要有三块,分别为:线程堆栈,用于分配值类型堆栈GC堆,用于分配小的对象实例(小于85000字节)LOH堆,用于分配大对象实例(不小于85000字节)内存分配中相关的IL指令:newobj,用于创建引用类型对象ldstr,用于创建string对象newarr,用于分配新的数组对象box,在值类型转换为引用类型对象时,将值类型字段拷贝到托管堆上发生的内存分配 值类型中的引用类型字段和引用类型中的值类型字段的内存分配对于值类型嵌套引用类型的情况,引用类型变量作为值类型的成员变量,在堆栈上保存该成员的引用,而实际上的引用类型仍保存在GC堆上(结构实例化)对于引用类型嵌套值类型
33、的情况,则该值类型将作为引用实例的一部分保存在GC堆上(类实例化)代龄垃圾收集器将托管堆中的对象分为三代,分别为:0,1,2 阙值分别为:256KB,2MB,10MB当有垃圾回收时,未被回收的对象代龄将提升一级仅当第0代对象释放的内存不足以创建新对象时,同时1代对象的体积也超出了容量阙值时,垃圾回收器将同时对第0代和第1代对象进行垃圾回收垃圾回收小结CLR 提供了一种分代式、标记清除型GC,利用标记清除算法来对不同代龄的对象进行垃圾收集和内存紧缩,保证了运算效率和执行优化一个对象没有被其他任何对象引用,则该对象被认为是可回收对象最好不要通过刁颖GC.Collect来强制执行垃圾回收垃圾对象并非
34、立即被执行内存清理,GC可以在任何时候执行垃圾收集对“胖”对象考虑弱引用,以提高性能Finalize方法规则在C#中无法显式重写Finalize方法,只有通过析构函数语法形式来实现struct中不允许定义析构函数,只有class中才可以,并且只能有一个Finalize方法不能被继承或重载析构函数不能加任何修饰符,不能带参数,也不能显式调用,唯一例外是在子类重写时,通过base调用父类Finalize方法,而且这种方式也被隐式封装在析构函数中执行垃圾回收执勤系统会自动执行终止化操作Finalize方法中,可以实现使得被清理对象复活的机制,不过这种操作相当危险,而且没有什么实际意义Finalize
35、方法和Dispose方法规则:对于非托管资源的清理,Finalize由GC自行调用,而Dispose由开发者强制调用尽量避免使用Finalize方式来清理资源,必须实现Finalize时,也应一并实现Dispose方法,来提供显式调用的控制权限通过GC.SuppressFinalize可以免除终结垃圾回收是,执行终结器的准确时间是不确定的,除非显式调用Dispose或者Close方法强烈建议不要重写Finalize方法,同时强烈建议在任何有非托管资源访问的类中同时实现终止化操作和Dispose模式Finalize和Dispose方法,只能清理非托管资源,释放内存仍由GC负责对象使用完毕应该立即
36、释放其资源,最好显式调用Dispose方法来实现性能条款推荐一Dispose模式来替代Finalize方式选择合适的垃圾手收集器:工作站GC和服务器GC在适当的情况下实现对对象的弱引用尽可能用using来执行资源清理推荐使用泛型集合来替代非泛型集合特定类型的Array性能优于ArrayList(向ArrayList添加其他值类型元素会发生装箱与拆箱操作)字符串滞留机,是CLR为string类型实现的特殊设计合理使用System.String和System.Text.StringBuilder(简单字符串用String复杂用StringBuilder)尽量在子类中重写ToString方法for和
37、foreach的选择以多线程处理应对系统设计尽可能少抛出异常,禁止将异常处理放在循环内捕获异常时,catch块中尽量指定具体的异常筛选器,多个catch块应该保证异常由特殊到一般的排列顺序Struct和class性能比较以is/as模式进行类型兼容性检查(is实现类型判断,as实现安全的类型转换)const和static readonly的权衡 (推荐static readonly)尽量使用一组零基数组new关键字new一个class是,new完成了以下两个方面的内容:一是调用newobj命令来为实例在托管堆中分配内存;二是用构造函数来实现对象的初始化new一个struct时,new运算符用于
38、调用其构造函数,实现实例初始化new一个int时,new运算符将其初始化为0new运算符不可重载new内存分配失败,将引发OutOfMemoryException异常this和base关键字base常用于派生类对象初始化时和基类进行通信base可以访问基类的公有成员和受保护成员,私有成员是不可访问的this指代对象本身base可以指向父类的方法有两种:一是有重载存在的情况下,base将指向直接继承的父类成员方法在没有重载的情况下可以指向任何上级父类的共有或者受保护方法base和this尽量少用或者不用base和this。除了决议子类的名称冲突和在一个构造函数中调用其他的构造函数之外,base和
39、this使用容易引起不必要的结果在静态成员中使用base和this是不允许的。原因是。Base和this访问都是泪的实例,也就是对象,而静态成员只能由类来访问。Base是为了实现多态而设计的使用this或base关键字只能指定一个构造函数,也就是说不可同时将this和base作用在一个构造函数上。简单来说,base用于在派生类中访问重写的基类成员;而this用于访问本类的成员,当然也包括继承而来的共有成员除了base,访问基类成员的令外一种方式是:显式类型转换来实现的using说明using引入的是逻辑结构,C语言中的#include引入物理类库using引入命名空间并不等于一定会被加载,只有
40、用到时才加载using一般放在C#源文件开头,但不是强制的null规则null为引用类型变量的默认值,为引用类型的概念范畴null不同于0、”、string.Empty引用is或as模式对类型惊喜判断或装换是,需要进一步的null检查判断一个变量是否为null,可以应用=或!=操作符来完成对任何值为null的变量操作,都会抛出NullReferenceException异常可空类型小结可控类型表示为null的值类型不允许使用嵌套的可空类型,例如Nullable<Nullable<T>>Nullable<T>和T?是等效的对可空类型执行GetType方法,将返
41、回类型T,而不是Nullable<T>C#允许可控类型上执行转换和转型,例如Int? a=100;Int32 b=(Int32)a;a=null;int? c=(int?)200;Null Object模式小结有效解决对象为空的情况,为值为null提供可靠保证保证能够返回有效的默认值,例如在一个List<User> userList中能够保证任何情况下都有有效值返回,可以保证usrList操作的有效性提供统一判定的IsNull属性null object要保持原object的所有成员的不变性,所以是我们常常将其实现为Sigleton模式expicit,用于声明必须强制转换
42、的自定义类型转换操作符implicit,用于声明隐式的自定义类型转换操作符使用转换运算符进行类型转换的一般规则所有转换必须是static的类型转换可能存在信息丢失或者精度损失,对于有损转换,最好提供显式的类型转换,并且这种有损转换不被允许时,应在显式转换中抛出IvalidCastException异常用户定义运算符不能是封闭类型对象,也不能装换成封闭类型对象,否则将引发编译时异常,例如public static implicit operator MyAge(MyAge age)return age;显式和隐式转换是个值得权衡的选择:隐式转换较为灵活,可读性强,但必须保证不会引发异常或者发生有
43、损转换,否则会引起不必要的转换结果,这种情况下则实现为显式转换较为妥当运算符只能按值传递,不能按引用传递,因此不能采用ref和outyield应用规则yield只能应用于迭代器中,无论yield return返回何种方法类型,方法必须返回以下的接口类型:System.Collections.Gereic.IEnumerable<T>、System.Collections.IEnumerable、System.Colections.Generic.IEnumerator<T>或System.Colections.IEnumerator。yield语句不允许应用于不安全块中
44、yield return不支持带有ref或者呕吐参数,因为那会使得状态机难以维护yield语句不能应用于匿名方法中yield语句不能出现在catch块中,或者包含catch字句try块中,也不能出现在finally块中lock小结lock对象必须是引用类型参数避免锁定公共对象或不受应用程序控制的对象实例,最好定义private对象来锁定string类型对象对多线程操作=是安全的,因此不建议锁定字符串类型对象。事实上,由于字符串的驻留机制,在整个应用程序中可能只有一个实例,字符串锁定可能会导致不必要的阻塞或死锁避免死锁。让两个线程以相同的加锁顺序锁定对象,是避免死锁的有效手段Monitor类还提
45、供了一个TryEnter方法,使用上更加灵活。二者区别是,lock会一致等待锁定对象释放后下一线程才能进入;而TryEnter会返回当前线程是否获取该锁,是则返回true,否则返回false线程同步最好只应用在需要的时候,因为锁定对象对系统性能存在影响:一方面是加锁的系统开销;另一方面可能导致其他线程因为等待释放对象而暂停执行sealed不能喝abstract公用,因为密封类不能被继承,而抽象类又总希望被继承,二者语意抵触,不可共存定义密封方法,sealed必须和override一起使用性能优化,一方面是密封类不用作基类,另一方面对于密封类成员的虚方法调用将转换为非虚方法的处理机制,因此在成本
46、上略高于虚方法的执行机制string类型是密封的struct是隐式密封的,因此不能被继承,例如System.Decimal等密封类一个常见的应用就是:当一个类只有静态成员时,可以考虑将其实现为密封类,例如.NET框架中的System.Math、System.Drawing.Pen等const、readonly和static readonlyconst、readonly和static readonly定义的我常量,指定初始值后(包括在构造函数内指定初始值)将不可更改,可读不可写const必须在声明时指定初始值;而readonly和static readonly在声明时可以指定也可以不指定初始值,
47、同时也可以在构造函数内指定初始值,如果同时在声明时和构造函数内指定初始值,以构造函数内指定的值为准const和static readonly定义的常量是静态的只能由类型直接访问;而readonly定义的常量是非静态的,只能由实例对象访问static readonly常量,如果在构造函数内指定初始值,则必须是静态无参构造函数const可以定义局部变量和字段;而readonly 和static readonly不能定义局部变量,只能定义字段常量。实际上,readonly应该称之为只读字段,因此局限于定义字段;而const才是常量,可以定义字段和局部变量 struct中不可以有无参的构造函数 抽象类
48、和接口比较请记住,面向对象的一个重要原则就是:面向接口编程面向抽象编程,通过封装变化来实现实体间的关系抽象类应着重于关系密切的对象,而接口最适合为不相关的类提供通用的功能接口着重于CAN-DO关系类型,而抽象类偏重于IS-A式关系接口多定义对象的行为;而抽象类多定义对象的属性接口的定义可以使用public、protected、internal、和private修饰符,大部分接口都被定义为public,另外方法的访问级别不能低于接口的访问级别,否则将导致编译错误“接口不变”,是应该考虑的重要因素。所以在由 接口扩展时,应增加新的接口,而不能更改现有接口尽量将接口设计成功能单一的功能块在接口中所有
49、方法都默认为public如果预计会出现版本问题,可创建抽象类。而向接口中添加新成员则会强制要求修改所有派生类,并重新编译,所以版本式的问题最好以抽相类来实现从抽象类派生出的非抽此昂类必须包括继承的所有抽象方法和抽象访问器的实现对抽象类不能使用new关键字,也不能被密封,原因是抽象类不能被实例化抽象方法声明中不能使用static或virtual修饰符is模式检查对象类型的兼容性,并返回结果:true或false不会抛出异常如果对象为null,则返回值永远为false典型用法为:class ISSample public static void object o=new object(); /执行
50、第一次类型兼容性检查 if(o is ISSample) /执行第二次类型兼容性检查 ISSample a=(ISSample)o;as模式检查对象类型的兼容性,并返回结果,如果不兼容就返回null不会抛出异常如果结果判断为空,则强制执行类型转换将抛出NullReferenceException异常as必须和引用类型一起使用典型用法为:class ASSample public static void Main() object o=new object(); /执行一次兼容性检查 ASSample b=o as ASSample; if(b!=null) /执行关于b操作虚方法不能是静态的、
51、密封的覆写实现的多态确定于运行时,因此更加灵活;重载实现的多态确定于编译时,因此更加高效和简单静态构造函数和实例构造函数的比较静态构造函数可以和无参构造函数共存。虽然参数列表相同,但二者的执行时间不同,静态构造函数在运行库加载时执行;而实例构造函数则在实例创建时执行静态构造函数只能对静态成员进行初始化操作,不能作用于非静态成员;而实例构造函数,可以初始化实例成员和,也可以初始化静态成员,但静态只读字段除外静态构造函数只被执行一次,而.NET运行库也无法确定静态构造函数在什么时候被执行;而实例构造函数可以在多次实例创建时被执行多次一个类只能有一个静态构造函数;而一个类只能有多个实例构造函数静态字
52、段的初始值在静态函数调用之前被指定静态成员可以在声明时初始化,也可以通过静态构造函数初始化,这两种初始化只能被执行一次静态成员属于类所有,无论创建多少实例对象,静态成员在内存中只有一份ArrayList实现了IList、ICollection、IEnumerable和ICloneable接口代码:public class ArrayList: IList, ICollection, IEnumerable, ICloneableIEnumerable接口的定义可表示为:public interface IEnumerable IEnumerable GetEnumerable();/为fore
53、ach操作提供支持ICollection接口定义为:public interface ICollection:IEnumerable void CopyTo(Arrary arry ,int index);/将集合拷贝到数组 int Count get;/条目数量 bool IsSynchronized get;/支持线程同步操作 object SyncRoot get;/支持线程同步操作IList接口定义为public interface IList:ICollection, IEnumerable int Add(object value);void Clear();bool Contai
54、ns(object value);int IndexOf(object value);void Insert ( int index,object value);void Remove (object value);void RemoveAt(int index);bool IsFixedSize get;bool IsReadOnly get;object this int index get;set;ArrayList和Array较相同点:ArrayList和ArrayList均实现了相同的接口,因此具有很多操作方法都相同,例如对自身进行枚举,能够foreach遍历集合成员等Array和A
55、rrayList创建的对象均存储在托管堆中不同点:Array只能存储同构对象,不过声明为Object类型的数组除外,因为任何类型都可以隐式转换为Object类型;ArrayList可以存储异构对象,这是因为在本质上ArrayList内部维护着一个Object items类型字段。在应用ArrayList时,应考虑装箱与拆箱带来的性能损失。Array可以是一维的,也可以是多维的;ArrayList只能是一维的Array的容量是固定的,一旦声明不可更改;ArrayList的容量是动态增加的。添加元素超过初始容量时,ArrayList会根据需要重新分配,还可以通过TirmToSize方法将其空项删除来压缩体积Array下限可以设置;而ArrayList的下限只能为0Array只有简单的方法来完成对元素的操作,不能随意增加或删除数组元素;ArrayList提供了丰富的方法来完成对元素的操作对空数组元素进行操作可能会引发异常,因此操作之前判断是否为空是很有必要的Queue和StackQueue和stack的默认值不同,Queue为32,而Stack为10关于Queue方法:Enqueue用于向对尾添加元素,Dequeu
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 广东省潮州市饶平县2025-2026学年高三上学期8月联考物理试卷
- 第五章 质量与密度 本章综合训练(含答案) 2025-2026学年物理沪粤版(2024)八年级上册
- 运动学题库及答案简单
- 2025学年湖北省部分学校高二语文上学期开学测试卷附答案解析
- 山西省晋城市2022-2023学年八年级上学期期末语文试卷(含答案)
- 国职五级滑雪题库及答案
- 扫雪除冰安全教育培训课件
- 2025年礼仪考试综合题目及答案
- 2025年德育教育考试试题及答案
- 2025年广东数学学考试卷及答案
- 行动的力量课件
- 会计信息系统 课件 第0-2章 导学、会计信息系统概述、电商企业会计信息系统搭建
- 2024广西继续教育公需科目(高质量共建“一带一路”)真题
- 上海市内分泌科临床质控手册
- 教科版六年级科学上册知识清单(新版)
- 装饰装修工程施工方案(完整版)
- 人教版(2024)小学信息科技 三年级 第3课《体验人机交互》教学设计
- 《机械常识》(第二版) 课件 第一章 常用金属材料
- 燃气市场风险分析报告
- 人教部编版小学五年级语文上册第一、第二单元测试题
- 四宫格数独课件
评论
0/150
提交评论