C# 值类型构造函数
🏷️ C#
创建一个值类型 Point
,一个引用类型 Rectangle
。
csharp
namespace StructCtorSample
{
class Program
{
static void Main(string args)
{
Rectangle rc = new Rectangle();
Point p = new Point();
}
}
struct Point
{
public int m_x, m_y;
}
class Rectangle
{
public Point m_topLeft, mbottomRight;
}
}
编译后的 IL 代码如下:
点击查看 IL 代码
cs
.class private auto ansi beforefieldinit StructCtorSample.Program
extends [mscorlib]System.Object
{
.method private hidebysig static void Main(string args) cil managed
{
.entrypoint
// 代码大小 16 (0x10)
.maxstack 1
.locals init ([0] class StructCtorSample.Rectangle rc,
[1] valuetype StructCtorSample.Point p)
IL_0000: nop
IL_0001: newobj instance void StructCtorSample.Rectangle::.ctor()
IL_0006: stloc.0
IL_0007: ldloca.s p
IL_0009: initobj StructCtorSample.Point
IL_000f: ret
} // end of method Program::Main
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// 代码大小 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method Program::.ctor
} // end of class StructCtorSample.Program
.class private sequential ansi sealed beforefieldinit StructCtorSample.Point
extends [mscorlib]System.ValueType
{
.field public int32 m_x
.field public int32 m_y
} // end of class StructCtorSample.Point
.class private auto ansi beforefieldinit StructCtorSample.Rectangle
extends [mscorlib]System.Object
{
.field public valuetype StructCtorSample.Point m_topLeft
.field public valuetype StructCtorSample.Point mbottomRight
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// 代码大小 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method Rectangle::.ctor
} // end of class StructCtorSample.Rectangle
注意看一下两个变量的创建指令:
cs
IL_0001: newobj instance void StructCtorSample.Rectangle::.ctor()
IL_0009: initobj StructCtorSample.Point
Rectangle
实例是使用 newobj
指令;Point
实例则是只使用了 initobj
指令;
可以看一下 读《你必须知道的 .NET》IL 指令笔记 中对这两个指令的描述。
再看一下 Point
类和 Rectangle
类的实例代码,可以发现 Point
类里根本就没有构造函数,而 Rectangle
类则自动生成了 ctor
方法。
那么我们显示的创建构造函数呢?编译器会不会就可以自动调用了呢?
修改一下 Point
类型追加一个无参构造函数:
csharp
struct Point
{
public int m_x, m_y;
Point()
{
m_x = m_y = 5;
}
}
结果却是编译出错了:
结构不能包含显式的无参数构造函数
原因是:C# 不允许值类型自定义无参构造函数。
但其实 CLR 中是允许的。那 C# 为什么不允许呢?当然是有原因的啦。
还是回到创建变量时的指令,值类型是使用 initobj
指令创建的,该指令只完成值类型的初始化,并不调用构造函数,也就是说即使值类型有构造函数,也不会自动调用。
就像上面 Point
的无参构造函数,我们预想的是 xy 值为 5,若结果创建对象后还是 0,会让程序猿感觉很困惑,所以C# 默认禁止了值类型创建无参构造函数。
但 C# 是允许创建有参构造函数的,但是有一点要注意,必须在构造函数中为所有的字段设定值,否则编译时会报如下错误。
在控制返回到调用方之前,字段“StructCtorSample.Point.m_y”必须完全赋值
值类型有参构造函数的示例:
csharp
struct Point
{
public int m_x, m_y;
Point(int x, int y)
{
m_x = x;
m_y = y;
}
}