我们知道,C# 语言的构造函数的名称和类名相同。
静态构造函数最多只能有一个。不能有返回值,不能有参数,不能有访问修饰符。
实例构造函数可以有多个。不能有返回值,可以有参数,可以有访问修饰符。
如果没有为对象提供实例构造函数,则 C# 编译器将创建一个默认的实例构造函数,该构造函数实例化对象,并将所有成员变量设置为默认值。
1 using System;
2 using System.Diagnostics;
3
4 namespace Skyiv.Bin
5 {
6 public class Foo
7 {
8 static Foo()
9 {
10 Console.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name);
11 }
12
13 public Foo()
14 {
15 Console.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name);
16 }
17
18 protected void Bar()
19 {
20 Console.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name);
21 }
22
23 private static void Main()
24 {
25 Console.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name);
26 new Foo().Bar();
27 }
28 }
29 }
上述 C# 程序的运行结果是:
C> Foo
.cctor
Main
.ctor
Bar
上述 C# 程序运行时首先调用静态构造函数(.cctor),接着调用 Main 静态方法,然后调用实例构造函数(.ctor),最后调用 Bar 实例方法。
也就是说,静态构造函数名称是 .cctor (我猜想这是 class constructor 的缩写),实例构造函数的名称是 .ctor (我猜想这是 constructor 的缩写)。这可以从下图的 IL 代码看出:
既然 C# 语言的构造函数的名称和类名相同,那么在 C# 语言中就无法再定义和类名相同名称的方法了。
那么下面的 Test.cs 是否合法呢?
1 namespace Skyiv.Bin
2 {
3 static class Test
4 {
5 static void Main()
6 {
7 Bar.Bar();
8 }
9 }
10 }
让我们看看下述的 Bar.cs 吧:
1 using System;
2
3 namespace Skyiv.Bin
4 {
5 public static class Bar
6 {
7 public static void Bar1()
8 {
9 }
10 }
11 }
首先使用 csc /t:library Bar.cs 命令将 Bar.cs 编译为 Bar.dll。
接着使用 ildasm /out:Bar.il Bar.dll 命令将 Bar.dll 反汇编为 Bar.il:
1
2 // Microsoft (R) .NET Framework IL Disassembler. Version 3.5.30729.1
3
4
5
6
7 // Metadata version: v2.0.50727
8 .assembly extern mscorlib
9 {
10 .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
11 .ver 2:0:0:0
12 }
13 .assembly Bar
14 {
15 .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
16 .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
17 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
18 .hash algorithm 0x00008004
19 .ver 0:0:0:0
20 }
21 .module Bar.dll
22 // MVID: {01B600EE-97DD-472C-AB80-D5087E640A51}
23 .imagebase 0x00400000
24 .file alignment 0x00000200
25 .stackreserve 0x00100000
26 .subsystem 0x0003 // WINDOWS_CUI
27 .corflags 0x00000001 // ILONLY
28 // Image base: 0x007E0000
29
30
31 // =============== CLASS MEMBERS DECLARATION ===================
32
33 .class public abstract auto ansi sealed beforefieldinit Skyiv.Bin.Bar
34 extends [mscorlib]System.Object
35 {
36 .method public hidebysig static void Bar1() cil managed
37 {
38 // 代码大小 2 (0x2)
39 .maxstack 8
40 IL_0000: nop
41 IL_0001: ret
42 } // end of method Bar::Bar1
43
44 } // end of class Skyiv.Bin.Bar
45
46
47 // =============================================================
48
49 // *********** 反汇编完成 ***********************
50 // 警告: 创建了 Win32 资源文件 Bar.res
将上述 Bar.il 文件第 36 行的 Bar1 改名为 Bar 。
然后再使用 ilasm /dll Bar.il 命令重新将 Bar.il 汇编为 Bar.dll。
最后,就可以使用 csc /r:Bar.dll Test.cs 来编译了。
可见,虽然 C# 语言不允许有和类名相同名称的(不是构造函数的)方法,但是 MSIL 是允许的,而且也能够在 C# 语言中调用该方法。
我建议修改 C# 语言规范,将静态构造函数的名称改为 .cctor,实例构造函数的名称改为 .ctor。
这样,不但可以和 MSIL 语言保持一致,而且有以下好处:
- 在 C# 程序中允许定义和类名相同名称的(不是构造函数的)方法。
- 对 C# 程序进行重构时,如果需要改变类名,就不用相应修改构造函数的名称了。
- 如果想拷贝一个类的代码来创建一个新类,也不用修改新类的构造函数的名称了。
不知各位朋友的看法如何?