无论学习那门语言都要学习函数体,C#,JAVA,PHP,都会涉及到函数体,而C#的函数体成员并不少,方法和构造器就是函数体成员之一,函数体成员还包括但不限于:方法,属性,构造器,终结器,运算符及索引器。
方法就是某个类相关的函数,也可以返回简单的基元类型或者什么也不反回,方法可以定义其公开性,如果使用static修饰符则变为静态方法。
属性是可以从客户端访问到的函数组,访问形式和访问类相同,C#为读写类中的属性提供了专用语法。
构造器是实例化对象时自动调用的特殊函数,必须与所属的类同名,且不能有返回类型,构造器用于初始化字段的值,可通过不同参数进行重载。
终结器类似与构造函数,但是CLR检测到不再需要某个对象时调用他,他的名称与类相同,但前面有一个~符号
运算符执行的最简单操作就是“+’“-’“*’“/’这些基本运算,C#也支持重载运算符
索引器允许对象以数组的或集合的方式进行索引。
构造器
以上就是函数体的基本成员和方法的基本定义,接下来我们先说一下构造器,为什么说构造器?
因为构造器实际上会帮我们很好的理解方法一个类的初始化过程,我们会发现无论是一个对象实体或是方法,大部分都会放在cs文件中,而构造器是初始化对象的,我建立了一个Student的类里面只有一个字段一个函数体,在Main函数中我初始化了Student类,运行就会发现构造器函数以及执行,并且调用了方法write
可以发现,当创建一个类型的实例时:
1)为实例的字段分配内存。
2)初始化对象的附加字段(类型对象指针和同步块索引)。
3)调用类型的实例构造器来设置对象的初始状态。
运行后输出的结果
实例构造器永远不能被继承。
因为实例构造器不能被继承,类只有类自己定义的实例构造器,所以就不能用virtual,new,override,sealed,abstract修饰符来定义构造器。 类型构造器可以用于接口(C#不允许这样做),引用类型,值类型。实例构造器用来设置一个类型某个实例的初始化状态,类型构造器用来设置一个类型的初始化状态。默认情况下,如果定义的类没有显式的定义一个构造器,编译器会默认的定义一个无参的构造器。在默认构造器的实现中,它只是简单的调用了基类的无参构造器。
当我们在值类型里面定义了一个类型构造器时,CLR不一定会调用这个静态构造器,例子创建的是无参类构造器,会在第一次初始化时创建,所以我们再次实例化stu的时候,控制台会输出“我是函数方法1”,如果一个类构造器的方法里,引入了其他类型定义了类型构造器,JIT会检测是否已经在AppDomain里面执行过。如果没有执行,则发起对类型构造器的调用,否则不调用。
当程序运行后,线程会开始执行并最终获取调用构造器的代码。实际上有可能会是多个线程执行同一个方法,CLR想要确保一个类型构造器在一个AppDomain里面只执行一次,当一个类型构造器被调用时,调用的线程会获取一个互斥的线程同步锁,这时如果有其他的线程在调用,则会阻塞。当第一个线程执行完后离开,其他的线程被唤醒并发现构造器的代码执行过了,所以不会继续去执行了,从构造器方法返回。CLR通过这种方式来确保构造器仅仅被执行一次。
提示:
由于CLR会确保类型构造器在每一个AppDomain里面只会执行一次,是线程安全的。所以如果要初始化任何单例对象(singleton object),放在类型构造器里面是再合适不过了。
静态构造器
静态构造函数是实现对一个类进行初始化的方法成员. 它一般用于对静态数据的初始化. 静态构造函数不能有参数,不能有修饰符而且不能被调用,当类被加载时,类的静态构造函数自动被调用.
在一个程序的执行过程中,静态构造器最多只执行一次.
静态构造器在类的静态成员初始化之后执行.或者说编译器会将静态成员初始化语句转换成赋值语句放在静态构造器执行的最开始.
静态构造器在任何类的静态成员被引用之前执行.
静态构造器在任何类的实例变量被分配之前执行.
类型构造器性能
调用类型构造器并不那么简单,JIT编译器不得不决定是否生成调用它的代码,并且CLR要确保调用是线程安全的。当编译器决定发起一个调用来执行类型构造器,它必须判断是否应该这样做,有两种可能性:
1.JIT在创建类型的第一个实例的代码之前立即发起或者在访问类的非继承的字段,成员的代码之前立即调用
2.JIT在首次访问一个静态字段,静态方法,实例方法,或调用一个实例构造器的代码之前某个时间调用,因为CLR要确保静态构造器在其他成员被访问之前运行。
构造函数中,还有一个特殊的存在, readonly
关键字是一个可在字段上使用的修饰符。 当字段声明包括 readonly
修饰符时,该声明引入的字段赋值只能作为声明的一部分出现,或者出现在同一类的构造函数中。
可以说
readonly一般只在构造器初始化的时候赋值,其余的时候不能改变他的值。
扩展方法
c# 扩展方法出来已久,介绍扩展方法的文章也很多,简单点说就是可以在不改变现有类的情况下给这个类添加方法。我觉得扩展方法的最大意义在于我们可以给那些我们根本无法修改的类,比如String,添加我们自定义的方法。既然无法通过修改来添加,那就只能通过扩展了。在使用扩展方法时,可以像调用实例方法那样调用静态方法。这就很大程度的方便了代码的开发。
扩展方法的基本原则:
(1).C#只支持扩展方法,不支持扩展属性、扩展事件、扩展操作符等。
(2).扩展方法(第一个参数前面是this的方法)必须在非泛型的静态类中声明,扩展方法必须有一个参数,而且只有第一个参数使用this标记。
(3).C#编译器查找静态类中的扩展方法时,要求这些静态类本身必须具有文件作用域。
(4).C#编译要求“导入”扩展方法。(静态方法可以任意命名,C#编译器在寻找方法时,需要花费时间进行查找,需要检查文件作用域中的所有的静态类,并扫描它们的所有静态方法来查找一个匹配)
(5).多个静态类可以定义相同的扩展方法。
(6).用一个扩展方法扩展一个类型时,同时也扩展了派生类型。
扩展方法不易乱用,尤其是在基类中扩展,其所有派生类都会有这个方法,很容易造成不应该出现的地方出现,另外扩展方法必须为*类,不能在嵌套类中使用扩展方法。扩展方法可以扩展很多种类型,包括但不限于,扩展委托,枚举,接口。
由于扩展方法可以在很多.netformwork提供的类库上使用扩展方法,例如:Enumerable,Queryable,String等等,也可以用于扩展异常方法,扩展枚举。本文篇幅有限,所以我们举其中一个示例。我们写一个如下的String扩展类,string是c#里面最最常用的类,和它的使用频度比起来,它的操作确少的可怜,实例方法只有三十个左右,静态方法只有十多个,
首先我们把string类最常用的静态方法IsNullOrEmpty扩展成“实例”方法:
只需要建立一个新的静态类,然后写一个方法名,将需要扩展的类参数前加上this就可以了。
在调用的时候,就可以直接把静态方法IsNullOrEmpty扩展成“实例”方法来调用。是不是就方便了很多,这只是一个抛砖引玉的例子。
在这里推荐一篇博文,博文里讲了很多具体的方法实例。
http://www.cnblogs.com/ldp615/archive/2009/08/07/1541404.html