《Microsoft .NET框架程序设计(修订版)》 第九章

本文详细介绍了C#中的实例构造器与类型构造器的工作原理,解释了操作符重载、转换操作符、引用参数及可变数目参数等概念,并探讨了虚方法的调用机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第九章 方法

Ø 9.1 实例构造器

如果希望类外的代码创建该类的实例,可以将构造器的访问限制设为私有方式。在创建一个引用类型的实例时,系统会执行以下三个步骤:首先为该实例分配内存,然后初始化对象的附加方法(即方法指针和一个SyncBlockIndex),最后调用类型的实例构造器设置对象的 初始状态。

当构造一个引用类型实例时,在调用其实例构造函数之前,系统为该对象分配的内存总是首先被设为0值。

默认情况下,对于引用类型,如果我们没有显式为其定义实例构造器,许多编译器都会为我们定义一个公有的无参构造器,通常称为默认构造器。

一个类的实例构造器在访问其基类的继承字段之前,必须调用其基类的实例构造器。

类型实例的创建不需要调用实例构造器的例子:

1. 调用ObjectMemberwiseClone方法将执行以下几步:为对象分配内存,初始化对象的附加成员,将源对象的字节拷贝到新创建的对象中。

2. 反序列化一个对象时,通常也不会调用构造器。

值类型构造器和引用类型构造器的工作方式的差别:

1. 首先CLR没有强制要求值类型中必须定义构造器方法

2. 很多编译器,包括C#,都不会为值类型产生默认的无参构造器。原因是值类型可以被隐式地创建。

3. C#不允许我们为一个值类型定义无参构造器,C#不允许值类型定义无参构造器是为了消除开发人员对于何时调用它们产生的混淆。如果不能定义无参构造器,编译器自然不会产生自动调用它的代码。没有无参构造器,值类型的字段将总是首先被初始化为0null

我们可以用另外一种语言,如IL汇编语言,来为值类型定义无参构造器。

为值类型定义的任何构造器都必须要初始化其所有的字段。

Ø 9.2 类型构造器

CLR支持类型构造器(又称静态构造器,类型构造器,或类初始化器)。类型构造器适用于接口(虽然C#不支持),引用类型和值类型。

类型构造器的访问限制应该总为私有方式,这由C#编译器自动来完成。(即为静态构造函数不允许出现访问修饰符)

CLR调用类型构造器的时间:

1. 在类型的第一个实例被创建之前,或者在类型的非继承字段或成员第一次被访问之前。

2. 在非继承静态字段被第一次访问之前的某一时刻。

类型构造器一旦被执行,它在整个应用程序域的生命周期都不会再次被调用。

类型构造器中的代码只能访问类型的静态字段,而且通常它的目的就是初始化这些静态字段。

类型构造器不应该调用其基类型的类型构造器。

Ø 9.3 操作符重载方法

访问修饰符必须是public,并且重载的操作符函数必须是静态static的。

Ø 9.4 转换操作符方法

和操作符重载方法一样,转换操作符方法必须为publicstatic

C#中我们使用implicit关键字来告诉编译器,在源代码中不必做显示的转型就可以产生调用转换操作符方法的代码;而使用explicit关键字来告诉编译器只用当源代码中指定了显示的转型时,才产生调用转换操作符方法的代码。

C#中,不能为一种转型操作符同时定义隐式转换操作符和显示转换操作符。

Ø 9.5 引用参数

当参数为引用类型的对象时,参数的传递是通过传递指向对象的引用(或指针)来完成的——注意引用/指针本身是按值传递的;对于值类型实例的参数来说,传递给方法的将是值类型实例的一个拷贝。这意味着方法会得到一份属于它自己的值类型实例的拷贝,而调用该方法的代码中的实例不会受到任何影响。

C#中,可以使用outref关键字是参数按引用的方式来传递。这两个关键字告诉C#编译器要产生额外的元数据来表示指定的参数是按引用的方式来传递的;编译器将使用该信息来产生传递参数地址的代码。

Outref的不同:如果一个方法的参数被标记为out,那么调用代码在调用该方法之前可以不初始化该参数,并且被调用方法不能直接读取参数的值,它必须在返回之前为该参数赋值。如果一个方法的参数被标记为ref,那么调用代码在调用该方法之前必须首先初始化该参数。被调用方法则可以任意选择读取该字段,或者为该参数赋值。

CLR允许我们根据outref参数来重载方法。下面的代码合法:

public class Class1

{

public void Method1(int i){ }

public void Method1(ref int i) { }

}

但是仅通过区分outref来重载方法又是不合法的,因为它们经过JIT编译后代码是相同的。

public class Class1

{

public void Method1(out int i){ }

public void Method1(ref int i) { }

}

在值类型参数上使用outref关键字与用传值的方式来传递引用类型的参数在某种程度上具有相同的行为。只有当一个方法要“返回”一个它未知的对象引用时,在引用类型参数上使用outref关键字才有意义。Outref修饰的引用类型参数的方法创建一个对象后,指向新对象的指针会被返回给调用代码。

区别于委托的协变与抗变,按引用方式传递的变量必须和方法声明的参数类型完全相同。

Ø 9.6 可变数目参数

只有方法的最后一个参数才可以用params关键字来标记。该参数必须为一个一维数组,但类型可以任意。传递null或者一个0长数组给该参数是合法的。

编写接受多个任意类型参数的方法:改变方法的原型使其接受一个Object数组即可。

Ø 9.7 虚方法的调用机制

一个类型可以有多个同名的方法,只要每个方法的参数集合或者返回值类型互不相同即可。大多数语言在确定方法的唯一性时,都要求名称相同的方法有一个不同的参数集合,而忽略返回值的差别。

所有的实例方法都会接受一个隐藏的this指针作为方法的第一个参数。其中this指针指向当前正在操作的对象。

Ø 9.8 虚方法的版本问题

使用new关键字可以隐藏方法的基类版本。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值