c#语言构造方法,C#构造函数

引用类型的实例构造函数不能被继承(不过,可以通过 base 关键字调用父类的构造函数),它负责初始化类型的实例字段。

对于静态字段,由静态构造函数负责。当然,也可以在实例构造函数中为静态成员赋值,但是,当之后更改这个值,再创建一个新的实例时,你会发现值又被实例构造函数改回去了。

所以,通常在静态构造函数中为静态成员赋值 (因为它只会执行一次)。

如果类型没有定义任何构造函数,C# 会生成一个无参实例构造函数(.ctor),它遍历类 型中所有的成员,并将它们设置为默认值。

可以声明多个不同的构造函数。可以利用 this 关键字来调用其他构造函数。例如:

public class AClass

{

public int i;

public static int j;

static AClass()

{

j = 2;

Console.WriteLine("静态构造函数");

}

public AClass() : this(5)

{

Console.WriteLine("实例构造函数");

}

public AClass(int i)

{

this.i = i;

Console.WriteLine("有参数的实例构造函数");

}

}

在这个例子中,我们使用下面的代码新建实例:

static void Main(string[] args)

{

var a = new AClass();

Console.WriteLine(a.i);

var b = new AClass(10);

Console.WriteLine(b.i);

Console.ReadKey();

}

根据规则,创建 a 时,调用无参的构造函数。但无参的构造函数调用了有参的构造函数,所以,先执行有参的构造函数,将 i 设置为 5,再执行无参的构造函数。

创建 b 则只调用有参的构造函数。最后的输出结果如下图所示。

0416a019abdc3942b67620f43f4399cf.gif

实例构造函数(值类型)

如果没有为结构定义构造函数,则 CLR 会生成一个默认的,将其成员初始化为默认值。

如果你自定义一个结构体的构造函数,那么必须初始化它的所有成员。结构的自定义构造函数不会被自动调用,所以你要手动地通过 this 来调用。

不能显式地为结构声明无参数的构造函数。

静态构造函数

静态构造函数又称类型构造函数,是一个特殊的构造函数,它会在这个类型第一次被实例化或引用任何静态成员之前执行,它具有以下特点:

静态构造函数既没有访问修饰符,也没有参数。

在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数来初始化类(的类型对象)。静态构造函数只会执行一次。

无法直接调用静态构造函数。它的访问修饰符是 private(不需要写明)。在程序中,用户无法控制何时执行静态构造函数。

静态构造函数不应该调用基类型的静态构造函数。这是因为类型不可能有从基类型继承的静态字段。

只有在类型包括静态字段且在定义时有赋值动作,C# 才会自动生成一个静态构造函数。

静态构造函数的目的是为了安全地给静态成员赋值。你可以显式定义静态构造函数为静态成员赋值。

如果什么都不做,它通过元数据得知这个类型有什么静态成员,并在其中初始化这些静态成员为默认值。

静态构造函数默认是没有的。因为它的功能是确定的(为静态字段赋值),而且只运行一次。

所以,它不需要访问修饰符和参数。如果没有显式定义,而且,没有在代码中为静态成员赋值,则 C# 不会自动生成静态构造函数。

例如,为静态成员赋值会导致 IL 岀现 .cctor:

class ExampleRef

{

private int a;

private string b;

private static string c = "static";

这会令 C# 在 .cctor 中初始化静态成员:

.method private hidebysig specialname rtspecialname static void .cctor () cil managed

{

// Method begins at RVA 0x208f

// Code size 11 (0xb)

.maxstack 8

IL_0000: Idstr "static"

IL_0005: stsfld string TypeFundamentalLab.ExampleRef::c

IL_000a: ret

} // end of method ExampleRef::.cctor

如果去掉赋值语句:c = "static",则不会生成静态构造函数。如果一个类型没有静态字段,那么更不需要自动生成静态构造函数了。

当创建第一个实例之前,堆上没有类型对象,所以要调用静态构造函数,引用静态成员之前,堆上也没有类型对象,而静态成员属于类型对象的一部分,所以也要调用静态构造函数。

这两种情况的最终结果,都是堆上最终出现了一个类型对象。因为类型对象只需要建立一次,所以这个静态构造函数也只能运行一次。在这之后,所有的实例对象都指向这个类型对象。

由于 C# 设计成不让外界直接访问静态构造函数,为静态构造函数设置访问修饰符(例如,设置为 public)或传入参数都是没有意义的,因为不可以主动调用。

静态构造函数只负责初始化静态成员,为类型对象的创建而服务,它和类型的实例对象没有关系。

构造函数的执行顺序

如果存在一个父类和继承它的子类,那么:

执行静态构造函数(先子类后父类)。在这一步中,如果发现父类或子类的静态构造函数已经执行过,那么就不会再次执行

执行实例构造函数(先父类后子类)。在这一步中,如果遭遇 this,则先调用 this 后面指向的实例构造函数的重载,然后再执行自己。

如果父类的实例构造函数是私有的,那么子类构造函数无法通过编译:

class Father

{

public static int i;

static Father()

{

i = 1;

Console.WriteLine("父类型的静态构造函数");

}

Father()

{

Console.WriteLine("父类型的实例构造函数");

}

}

class Son : Father

{

public static int j;

static Son()

{

j = 1;

Console.WriteLine("子类型的静态构造函数");

}

Son()

{

Console.WriteLine("子类型的实例构造函数");

}

}

上面的代码中父类 Father 的实例构造函数没有访问修饰符,因此,默认会使用 private。

子类的实例构造函数便无法访问父类的实例构造函数,不能通过编译,如下图所示。

7e271574ffb768fa423fcc92cecaddb7.gif

即使去掉显式定义的 Son 方法,结果也是一样。因此,这可以证明子类的实例构造函数确实会调用父类的实例构造函数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值