CLR类型设计之方法与构造器
无论学习那门语言都要学习函数体,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
CLR类型设计之方法与构造器的更多相关文章
- CLR类型设计之泛型(二)
在上一篇文章中,介绍了什么是泛型,以及泛型和非泛型的区别,这篇文章主要讲一些泛型的高级用法,泛型方法,泛型接口和泛型委托,协变和逆变泛型类型参数和约束性,泛型的高级用法在平时的业务中用的不多,多用于封 ...
- CLR类型设计之泛型(一)
在讨论泛型之前,我们先讨论一下在没有泛型的世界里,如果我们想要创建一个独立于被包含类型的类和方法,我们需要定义objece类型,但是使用object就要面对装箱和拆箱的操作,装箱和拆箱会很损耗性能,我 ...
- CLR类型设计之参数传递
写到这篇文章的时候,笔者回忆起来以前的开发过程中,并没有注意参数的传递是以值传递还是引用传递的,也是第一次了解到可变参数params,常用的不一定就代表理解,可能只是会用.接下来我们就一起回忆一下关于 ...
- CLR类型设计之属性
在之前的随笔中,我们探讨了参数,字段,方法,我们在开始属性之前回顾一下,之前的探讨实际上串联起来就是OOP编程的思想,在接下来的文章中,我们还会讨论接口(就是行为),举个例子:我们如果要做一个学生档案 ...
- CLR类型设计之类型之常量和字段
前言 孔子说:温故而知新,可以为师矣.所以对于学习过的知识要多复习,并且每一次复习都要尽可能的去扩展,而不是书本上的几句理论知识.很多人都喜欢分享自己的学习内容,记录下生活的点点滴滴 ...
- 设计一个方法injectBeforeAsyncSend,能够实现如下功能:在发起异步请求之前打印出请求的类型、URL、method、body、timestamp 等信息。
异步请求逻辑注入 工作中我们需要对异步请求的请求信息打印日志,但是又不能耦合在业务代码中打印.请设计一个方法injectBeforeAsyncSend,能够实现如下功能:在发起异步请求之前打印出请求的 ...
- 重温CLR(六)方法和参数
实例构造器和类(引用类型) 构造器是将类型的实例初始化为良好状态的特殊方法.构造器方法在“方法定义元数据表”中始终叫做.ctor(constructor的简称).创建引用类型的实例时,首先为实例的数据 ...
- 深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)
作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://zh.lucida.me/blog/java-8-lambdas-insideout-language- ...
- 【Clr in c#】方法
1. 引用类型(class)与值类型(strust)的构造函数(实例构造器) 1, 创建一个引用类型的实例时,首先为实例的数据字段分配内存,然后初始对象的附加字段,最后调用实例构造器来设置对象的初始 ...
随机推荐
- Linux常见命令集锦
这是平常用到的命令在这里做一下总结: 一.python 类1.pip(已安装)pip用来安装来自PyPI(https://www.python.org/)的python所有的依赖包,并且可以选择安装任 ...
- HDU1205 吃糖果
吃糖果 Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Total Submis ...
- 使用beanstalkd实现定制化持续集成过程中pipeline
持续集成是一种项目管理和流程模型,依赖于团队中各个角色的配合.各个角色的意识和配合不是一朝一夕能练就的,我们的工作只是提供一种方案和能力,这就是持续集成能力的服务化.而在做持续集成能力服务化的过程中, ...
- 使用邮件监控Mxnet训练
1. 前言 受到小伙伴的启发,就自己动手写了一个使用邮件监控Mxnet训练的例子.整体不算复杂. 2. 打包训练代码 需要进行监控训练,所以需要将训练的代码打包进一个函数内,通过传参的方式进行训练.还 ...
- DevOps之基础设施
唠叨话 关于德语关我屁事的知识点,仅提供精华汇总,具体知识点细节,参考教程网址,如需帮助,请留言. <信息技术(IT )> 关于IT信息技术的基础设施,知识与技能的层次(知道.理解.运用) ...
- vmware虚拟机安装CentOS-6.5教程
linux是企业最常用的服务器系统之一,CentOS是免费的,所以用的企业也挺多,今天给大家分享怎么在自己电脑的虚拟机中安装CentOS-6.5,以便用来玩耍,没事的时候可以学学linux的一些知识. ...
- JavaScript注释之HTML注释(<!-- & //-->)
JavaScript中支持HTML注释 //用法 <script language="javascript"> <!-- alert("我是注释内的JS ...
- MongoDB固定集合(Capped Collections)
MongoDB 固定集合(Capped Collections)是性能出色且有着固定大小的集合,对于大小固定,我们可以想象其就像一个环形队列,当集合空间用完后,再插入的元素就会覆盖最初始的头部的元素! ...
- System.getProperty参数大全
System.getProperty()参数大全 #java.version Java Runtime Environment v ...
- 对于Swift的Enum,文档上没有说的
今天无意发现一个东西, 但是在文档上看了很多遍都没找到, 但是亲测是可行的, 那到底是什么呢? 以前我们定义枚举 会这样: enum Hello { case Item( String, Int) c ...