你必须知道的.net(学习笔记)

一、类型转换的基本规则
       任何类型都可以安全的转换为其基类类型,可以由隐式转换来完成;
   任何类型转换为其派生类型时,必须进行显示转换,转换的规则是:(类型名)对象名;
   使用GetType可以取得任何对象的精确类型;
   基本类型可以使用Covert类实现类型转换;
   除了string以外的其他类型都有Parse方法,用于将字符串类型转换为对应的基本类型;
   值类型和引用类型的转换机制称为装箱(boxing)和拆箱(unboxing)。

二、is/as操作符
     它们都是用于类型转换,提供对类型的兼容性判断,使类型转换控制在安全的范畴,as的执行效率比is高。
     is检查对象类型兼容性,返回结果true或者false,但不会抛出异常,若对象为NULL则返回值为false。
     as检查对象类型兼容性,返回结果,若不兼容就返回NULL,不会抛出异常,如果结果判断为空,则强制执行类型转换将抛出NullReferenceException异常。

三、抽象类和接口的相同点和不同点
  相同点
     都不能被直接实例化,都可以通过继承实现其抽象方法。
     都是面向抽象编程的技术基础,实现了诸多的设计模式。
  不同点
     接口支持多继承;抽象类不能实现多继承。
     接口只能定义抽象规则;抽象类既可以定义规则,还可能提供已实现的成员。
     接口是一组行为规范;抽象类是一个不完全的类,着重族的概念。
     接口可以用于支持回调;抽象类不能实现回调,因为继承不支持。
     接口只包含方法、属性、索引器、事件的签名,但不能定义字段和包含实现的方法;抽象类可以定义字段、属性、包含有实现的方法。 
     接口可以作用于值类型和引用类型;抽象类只能作用于引用类型。例如,Struct就可以继承接口,而不能继承类。

四、抽象类和接口的应用场合
     抽象类应主要用于关系密切的对象,而接口最适合为不相关的类提供通用功能。
     接口着重于CAN-DO关系类型,而抽象类则偏重于IS-A式的关系;
     接口多定义对象的行为;抽象类多定义对象的属性;
     接口定义可以使用public、protected、internal 和private修饰符,但是几乎所有的接口都定义为public,原因就不必多说了。
     “接口不变”,是应该考虑的重要因素。所以,在由接口增加扩展时,应该增加新的接口,而不能更改现有接口。
     尽量将接口设计成功能单一的功能块,以.NET Framework为例,IDisposable、IDisposable、IComparable、IEquatable、IEnumerable等都只包含一个公共方法。
     接口名称前面的大写字母“I”是一个约定,正如字段名以下划线开头一样,请坚持这些原则。
     在接口中,所有的方法都默认为public。
     如果预计会出现版本问题,可以创建“抽象类”。例如,创建了狗(Dog)、鸡(Chicken)和鸭(Duck),那么应该考虑抽象出动物(Animal)来应对以后可能出现风马牛的事情。而向接口中添加新成员则会强制要求修改所有派生类,并重新编译,所以版本式的问题最好以抽象类来实现。
     从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实实现。
     对抽象类不能使用new关键字,也不能被密封,原因是抽象类不能被实例化。
     在抽象方法声明中不能使用 static 或 virtual 修饰符。
            如果要设计小而简练的功能块,则使用接口。如果要设计大的功能单元,则使用抽象类。
            抽象类是提取具体类的公因式,而接口是为了将一些不相关的类“杂凑”成一个共同的群体。至于他们在各个语言中的句法,语言细节并不是我关心的重点。

五、class和struct的区别
       class和struct最本质的区别就在于class是引用类型,内存分配于托管堆;而struct是值类型,内存分配于线程的堆栈上。
   class是引用类型,继承自System.Object类;struct是值类型,继承自System.ValueType类,因此不具多态性。但是注意,System.ValueType是个引用类型。
   从职能观点来看,class表现为行为;而struct常用于存储数据。
   class支持继承,可以继承自类和接口;而struct没有继承性,struct不能从class继承,也不能作为class的基类,但struct支持接口继承
   class可以声明无参构造函数,可以声明析构函数;而struct只能声明带参数构造函数,且不能声明析构函数。因此,struct没有自定义的默认无参构造函数,默认无参构造器只是简单地把所有值初始化为它们的0等价值
   实例化时,class要使用new关键字;而struct可以不使用new关键字,如果不以new来实例化struct,则其所有的字段将处于未分配状态,直到所有字段完成初始化,否则引用未赋值的字段会导致编译错误。
   class可以实抽象类(abstract),可以声明抽象函数;而struct为抽象,也不能声明抽象函数。
   class可以声明protected成员、virtual成员、sealed成员和override成员;而struct不可以,但是值得注意的是,struct可以重载System.Object的3个虚方法,Equals()、ToString()和GetHashTable()。
   class的对象复制分为浅拷贝和深拷贝(该主题我们在本系列以后的主题中将重点讲述,本文不作详述),必须经过特别的方法来完成复制;而struct创建的对象复制简单,可以直接以等号连接即可。
   class实例由垃圾回收机制来保证内存的回收处理;而struct变量使用完后立即自动解除内存分配。
   作为参数传递时,class变量是以按址方式传递;而struct变量是以按值方式传递的。
       可以简单的理解,class是一个可以动的机器,有行为,有多态,有继承;而struct就是个零件箱,组合了不同结构的零件。

六、何时使用struct
   实现一个主要用于存储数据的结构时,可以考虑struct。
   struct变量占有堆栈的空间,因此只适用于数据量相对小的场合。
   结构数组具有更高的效率。
   提供某些和非托管代码通信的兼容性。

七、new的用法
     作为运算符, 用于创建对象和调用构造函数。
     作为修饰符,用于向基类成员隐藏继承成员。不可和override共存,原因是这两者语义相斥:new用于实现创建一个新成员,同时隐藏基类的同名成员;而override用于实现对基类成员的扩展。
     作为约束,用于在泛型声明中约束可能用作类型参数的参数的类型。new作为约束和其他约束共存时,必须在最后指定。
     使用new实现多态。

八、new作为运算符创建不同类型时的区别
     new一个class时,new完成了以下两个方面的内容:一是调用newobj命令来为实例在托管堆中分配内存;二是调用构造函数来实现对象初始化。
     new一个struct时,new运算符用于调用其带构造函数,完成实例的初始化。
     new一个int时,new运算符用于初始化其值为0。

九、new的其他规则
     new运算符不可重载。
     new分配内存失败,将引发OutOfMemoryException异常。
   
十、C#访问关键字
     base关键字调用基类上已被其他方法重写的方法,指定创建派生类实例时应调用的基类构造函数。
     this关键字限定被相似的名称隐藏的成员,将对象作为参数传递到其他方法,声明索引器。

十一、base和this的用法和用途
   base常用于,在派生类对象初始化时和基类进行通信。
   base可以访问基类的公有成员和受保护成员,私有成员是不可访问的。
   this指代类对象本身,用于访问本类的所有常量、字段、属性和方法成员,而且不管访问元素是任何访问级别。因为,this仅仅局限于对象内部,对象外部是无法看到的,这就是this的基本思想。另外,静态成员不是对象的一部分,因此不能在静态方法中引用this。
   在多层继承中,base可以指向的父类的方法有两种情况:一是有重载存在的情况下,base将指向直接继承的父类成员的方法。例如Audi类中的ShowResult方法中,使用base访问的将是Car.ShowResult()方法,而不能访问Vehicle.ShowResult()方法;而是没有重载存在的情况下,base可以指向任何上级父类的公有或者受保护方法,例如Audi类中,可以使用base访问基类Vehicle.Run()方法。
        对重写父类方法,最终指向了最高级父类的方法成员。

十二、base和this的使用规则
   尽量少用或者不用base和this。除了决议子类的名称冲突和在一个构造函数中调用其他的构造函数之外,base和this的使用容易引起不必要的结果。
   在静态成员中使用base和this都是不允许的。原因是,base和this访问的都是类的实例,也就是对象,而静态成员只能由类来访问,不能由对象来访问。
   base是为了实现多态而设计的。
   使用this或base关键字只能指定一个构造函数,也就是说不可同时将this和base作用在一个构造函数上。
   简单的来说,base用于在派生类中访问重写的基类成员;而this用于访问本类的成员,当然也包括继承而来公有和保护成员。
   除了base,访问基类成员的另外一种方式是:显示的类型转换来实现。只是该方法不能为静态方法。

十三、值类型和引用类型的使用场合
   值类型
       以类型的大小作为选择值类型或者引用类型的决定性因素。数据较小的场合,最好考虑以值类型来实现可以改善系统性能;
   结构简单,不必多态的情况下,值类型是较好的选择;
   类型的性质不表现出行为时,不必以类来实现,那么用以存储数据为主要目的的情况下,值类型是优先的选择;
   参数传递时,值类型默认情况下传递的是实例数据,而不是内存地址,因此数据传递情况下的选择,取决于函数内部的实现逻辑。值类型可以有高效的内存支持,并且在不暴露内部结构的情况下返回实例数据的副本,从安全性上可以考虑值类型,但是过多的值传递也会损伤性能的优化,应适当选择;
   值类型没有继承性,如果类型的选择没有子类继承的必要,优先考虑值类型;
   在可能会引起装箱与拆箱操作的集合或者队列中,值类型不是很好的选择,因为会引起对值类型的装箱操作,导致额外内存的分配。
   引用类型
       可以简单的说,引用类型是.NET世界的全值杀手,我们可以说.NET世界就是由类构成的,类是面向对象的基本概念,也是程序框架的基本要素,因此灵活的数据封装特性使得引用类型成为主流;
   引用类型适用于结构复杂,有继承、有多态,突出行为的场合;
   参数传递情况也是考虑的必要因素;

十四、值类型和引用类型的判等
       Equals,System.ValueType重载了System.Object的Equals方法,用于实现对实例数据的判等。
   ReferenceEquals,他用于比较两个实例对象是否指向同一引用地址,对值类型应用ReferenceEquals将永远返回false。
   ==,未重载的==的值类型,将比较两个值是否“按位”相等。未重载==的引用类型将比较两个对象是否引用地址,等同于引用类型的Equals方法。因此,很多的.NET类实现了对==操作符的重载,而==和equals方法的主要区别,在于多态表现上,==是被重载,而Equals是重写。

十五、参数传递
    值类型参数的按值传递是该值类型实例的一个拷贝,因此被调用方法操作的是属于自己本身的实例拷贝,因此不影响原来调用方法中的实例值。
    引用类型参数的按值传递该值类型地址的一个拷贝,因此被调用方法操作的是属于自己本身的地址拷贝,因此影响原来调用方法中的实例值。
    如果参数是值类型,则按引用传递时,传递的是值类型变量的引用,因此在效果上类似于引用类型参数的按值传递方式。
    如果参数是引用类型,则按引用传递时,传递的是引用的引用而不是引用本身,类似于指针的指针概念。
    不管参数本身是值类型还是引用类型,按引用传递时,传递的是参数的地址,也就是实例的指针。
十六、关于out和ref
    不管是值类型还是引用类型,按引用传递必须以ref或者out关键字来修饰,其规则是:
      方法定义和方法调用必须同时显示的使用ref或者out,否则将导致编译错误。
      CRL允许通过out或者ref参数来重载方法。
        相同点:从CRL角度来说,ref和out都是指示编译器传递实例指针,在表现行为上是相同的。
        不同点:使用的机制不同。ref要求传递之前的参数必须首先显示初始化,而out不需要。

转载于:https://www.cnblogs.com/liuweicfyj/archive/2009/03/05/1403696.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值