必读文:
(体会篇) 一、显式(explicit)转换和隐式(implicit)转换的一般概念int i = 100; Response.Write(i); // 这就是隐式 Response.Write(i.ToString()); // 这就是显式 一般来讲,尽量使用显式转换,隐式转换可以通过消除不必要的类型转换来提高源代码的可读性。但是,因为可以在程序员未指定的情况下发生隐式转换,因此必须注意防止令人不愉快的后果。 另外还有,基类与派生类,接口与类,接口与子接口等的显隐式转换。基本都建议为显式。 有时间的话,查看下“泛型”二、理解C#值类型与引用类型值类型:结构/枚举/数值/可空类型(System.Nulable<T>泛型结构体) - (reference.GetType().IsValueType = true)
引用类型:数组/用户定义的(类/接口/委托)/object(装箱)/string - (reference.GetType().IsValueType = false) 注意: 结构体可以实现接口(?) 引用类型可以派生成别的,可是值类型不行 引用类型的复制只复制对象的引用而非对象本身(参考堆栈),而值类型的复制是整个复制(也参考堆栈) 引用类型需要new 来创建实例(new 操作符暗示一个类实例的创建,但不一定必须暗示动态内存分配,这和C++中对指针的操作不同。) 不管string看起来多么象值类型,它实际上是引用类型(它在被重新赋值时,托管堆会重新给它的变量分配内存) 值类型(比如结构体)不要求托管堆在栈上分配内存,那么它们被存放(部署)在哪? 值类型总是分配在它声明的地方:作为字段时,跟随其所属的变量(实例)存储;作为局部变量时,存储在栈上。 类里面有值类型,结构体里面有引用类型,这种嵌套好复杂,文章里面有讲,暂时不想理会 反复的创建引用类型的实例,一定会损失性能,这个显尔易见 我们到底是要创建类还是结构呢? 是否用于数据存储?是否完全由一些数据成员存取呢?是否永远不会有子类?是否永远不会有多态?如果都是的话,那无疑应该选择结构体而非类。 尽可能的确保0为值类型的有效状态,不然出现Null而导致编译出错,oracle也同样适用,nvl(a,0)+nvl(b,0)而非a+b,容易产生Null值而出错。 尽量减少装箱及拆箱操作。耗费性能而且会引发奇怪的bug。三、泛型 MSDN中文详解: 通过使用泛型类型参数T,可以编写单个类,而不致引入运行时强制转换或装箱操作的成本或风险。 泛型可以重用代码、保护类型的安全、提高性能 泛型最常用于创建集合类 (如:BookCollection<T>) 泛型对应的非泛型为ArrayList,使用的命名空间为 泛型有:接口/类/委托/事件;同样可以被反射查到 可以约束某些数据类型访问该泛型 结构/类/new()/<某基类名>/<接口名称>/U(裸类型约束) 我看到where T: 上述几种,这个是判断T是否属于某(几)种特定的数据类型的意思吗? 裸类型约束:用作约束的泛型类型参数称为裸类型约束。当具有自己的类型参数的成员函数需要将该参数约束为包含类型的类型参数时 Kill me!真得用到的时候才能真正明白,暂时放下吧。具体的应用现在抱着文件看也没用,用到的时候再看吧,反正一般公司的类库都很完整ZZzz,至少需要用到的时候知道有这个东西多个方法。 四、抽象类/接口 以及 抽象方法/虚方法 、 sealed抽象类以及接口: 抽象类:>> public abstract classA{} 列举一个类所用到的行为,但不明确的实现每个行为,抽象类可以有自己已经实现过的方法; 不能被实例化,只能被继承; 它的派生类可以override其抽象方法,但不是必须的,但一旦派生类没有实现所有的抽象方法,那它也将同样视作抽象类。 所以,如果一个类要能被实例化(new),则必须实现其基类全部的抽象方法。 接口:>> public Interface IClassA{} 接口说白了,就是一个类的模型,里面啥都有,可啥也不给你实现,反正就是画了个模子,要用到就要一个一个的全部填满了才行,是全部实现喔,只实现一部分都是不行的。 比如,定义类,[返回值] [类名](参数); 再比如属性吧。[属性名]{get;set;} 再比如事件event [事件类] [事件名];到底我现在是要一个抽象类呢?还是一个接口呢?有什么不同呢?
1、一个类,只能继承到一个抽象类,但可以实现多个接口;public class ANewBie:AbstractA, IInterfaceA, IInterfaceB; 2、抽象类里面可以有已经实现过的方法,直接继承了就是,可是接口是模子,要用到里面的就用就是了 3、所以,一般都用抽象类,尤其是大型的项目中。而接口一旦被使用就很难去更改,所以基本只是使用到这个接口的类之间的通迅而已,让这些类保持一定的联系和相关性。反正一个类可以实现多个接口,一个接口少定义一点东西,基本都是一些小的功能性模块,这样用起来也是不错的。比如,我要定义一些形状,那就可以把长宽等作为属性给归在一个接口里面,用的时候,这些形状都被这个接口联系在一起了。
抽象方法(abstract)与虚方法(virtual):
虚方法和抽象方法主要都是体现了多态性,在覆盖重写重用上的不同。 1、一个类里有一个抽象方法就必须被定义成抽象类,反之,一个抽象类里面可以有非抽象方法。不可以实例化成对象,只能被继承。 2、抽象方法一定要被其派生类override,抽象方法一定要被重写,而虚方法可以被重写。(抽象方法 = 未实现的虚方法) 3、虚方法可以在基类中实现,但抽象方法却不可以。静态成员、构造以及析构方法不能为虚。 当你觉得一个方法要实现什么功能,并且知道怎么实现功能的时候,用虚方法; 当你知道方法要实现的功能,但对怎么实现不清楚的时候,用abstract。 以下摘自C#知识点一文:如果你在声明一个方法的时候用了virtual这个关键字,那么,在派生类中,你就可以使用override或者new关键字来弃用它或是忽略它. 如果你在父类中用了virtual这个关键字,而在其派生类中又没有用override或new关键字,而直接引用一个同名方法的话,编译器将会报错,并将以 new方式,即忽略派生类中的方法的方式来运行 实例 // Versioning\versioning.cs001: public class MyBase002: { 003: public virtual string Meth1()004: { 005: return "MyBase-Meth1";006: }007: public virtual string Meth2()008: { 009: return "MyBase-Meth2";010: }011: public virtual string Meth3()012: { 013: return "MyBase-Meth3";014: }015: }016:017: class MyDerived : MyBase018: { 019: public override string Meth1() // 覆盖020: { 021: return "MyDerived-Meth1";022: }023: public new string Meth2() // 用new来忽略024: { 025: return "MyDerived-Meth2";026: }027: public string Meth3() // 系统在这里将会有一个警告,并且将会隐藏方法Meth3()028: 029: 030: { 031: return "MyDerived-Meth3";032: }033:034: public static void Main()035: { 036: MyDerived mD = new MyDerived();037: MyBase mB = (MyBase) mD;038:039: System.Console.WriteLine(mB.Meth1());040: System.Console.WriteLine(mB.Meth2());041: System.Console.WriteLine(mB.Meth3());042: }043: } 输出: MyDerived-Meth1 MyBase-Meth2 MyBase-Meth3
如果你把第037行去掉,把039-041中的mB全部改为mD,输出又变为: MyDerived-Meth1 MyDerived-Meth2 MyDerived-Meth3 这又说明了什么呢,说明了派生类的对象只有在被父类重塑的时候,override和new关键字才会生效.呵呵,这样说的确有点难以理解,大家只有自己动手,才能搞清楚这其中的机关,所谓"实践是检验C#的唯一标准",哈哈!
五、其它
静态构造方法:无需定义访问修饰符因为没有意义,构造函数不能带参数,一个类只可以有一个静态的构造方法。 readonly / const / static: const和static的赋值,不能在构造方法中设置 readonly的赋值只能在构造方法中(虽然不须,有默认值) 都不能作为变量或者out参数传递给方法,但可以传递给构造方法。 const常量是隐式静态,但不可以加上static修饰符。
六、一些关键字:
1、sealed
密封,可以用在类/方法/属性等前面,意指“不可以被其它的类继承或者重写”,所以显然,密封类不可以同时是抽象类或者用来修饰接口。 所以,sealed类中的属性和方法,可以是public类型或private类型,但不可以是protected类型。 2、override 覆盖重写,重载方法的签名必须不同 - 即参数的名称、个数和类型必须不同,只有返回类型不同是不够的。 3、partial 很有趣的概念,就是一个类,可以由多个人去完全其中的各个部分,只要用了partial,那么在编译的时候,会把这些类合并在一起,组成一个类。:) 4、internal 内部成员只有在同一程序集(assemble)中的文件内才是可访问的。内部访问通常用于基于组件的开发,因为它使一组组件能够以私有方式进行合作,而不必向应用程序代码的其余部分公开。(web b/s的用得很少这个东东)