眾說周知,Main方法是.net程序的入口,那有什么方法可以在Main方法之前執行代碼呢?研究過.net的高人也許已經知道了方法。
為什么在.net中Main方法是程序入口呢?那么Main方法和其他非Main的方法有什么差異呢?看下面代碼:
public class Program { static void Main() { Console.WriteLine("Main"); } static void OtherMain() { Console.WriteLine("OtherMain"); } }
Main()和OtherMain()方法就是輸出的東西不一樣,那我們再看一看兩都的IL代碼吧::
.method private hidebysig static void Main() cil managed { .entrypoint // 代碼大小 13 (0xd) .maxstack 8 IL_0000: nop IL_0001: ldstr "Main" IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: ret } // end of method Program::Main
.method private hidebysig static void OtherMain() cil managed { // 代碼大小 13 (0xd) .maxstack 8 IL_0000: nop IL_0001: ldstr "OtherMain" IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: ret } // end of method Program::OtherMain
從兩者的比較我們可以看出Main方法生成的IL代碼多了一條“.entrypoint”的指令,.entrypoint”什么意思?隨便一看就知道是“進入點”,就是程序入口的意思了,而且一個程序(exe,非dll,dll是沒有的)只能找到一個.entrypoint”,不信你可以找找。要在Main方法之前執行代碼我們只要如下代碼的樣子,把入口改為OtherMain即可:
public class Program { static void Main() { Console.WriteLine("Main"); } static void OtherMain() { Console.WriteLine("OtherMain"); Main(); } }
編譯,再用強大的反匯編程序——IL 反匯編程序打開編譯好的exe文件,點擊菜單文件》轉儲。保存后再用文件編輯工具打開(如notepad),將“.entrypoint”移動到OtherMain()的下面,保存,結果如下。
.method private hidebysig static void OtherMain() cil managed { .entrypoint // 代碼大小 19 (0x13) .maxstack 8 IL_0000: nop IL_0001: ldstr "OtherMain" IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: call void Test.Program::Main() IL_0011: nop IL_0012: ret } // end of method Program::OtherMain
用ilasm編譯修改好的文件,生成exe,再運行。看看結束是什么,是不是在輸出“Main”之前輸出了“OtherMain"。如果是,那恭喜你,程序入口修改成功!大家可以動手試試。
如果你覺得這種方法太麻煩了,那有個簡單的方法。知道類型構造器(又稱靜態構造方法)嗎?不知道?那先知道什么是類型構造器再看下面的。
類型構造器會在類第一次被使用的初始化類,在類的其他代碼被執行前執行。想要在Main方法之前執行代碼只要在包含Main方法的類里加一個類型構造器不就可以了:
public class Program { static Program() { Console.WriteLine("我執行了,Main方法還沒執行哦!"); } static void Main() { Console.WriteLine("Main"); } }
因為Main方法也是一個類的靜態方法,也會符合CLR規范的。如果在類型構造器拋出一個異常,你知道會發生什么嗎?
如果高人還知道其他方法,可以在評論中留言。