不使用Visual Studio等IDE,只使用csc.exe和記事本構建一個C#控制台應用程式。 ...
csc.exe是C#的命令行編譯器(CSharpCompiler),可以編譯C#源程式成可執行程式。它與Visual Studio等IDE(Integrated Development Environment,集成開發環境)的區別是,csc.exe只是將用C#語言編寫的源程式文件編譯成.exe、.dll等文件,它只是一個編譯器,而IDE提供豐富的調試、運行功能,提供很多view視圖以及解決方案管理器等文件組織功能。
csc.exe包含在.NET Framework SDK(Software Development Kit)中,除了csc.exe外,SDK還包括其他語言的編譯器,如vbc.exe(vb語言的編譯器)以及其他一些可能會用到的工具、文檔等。.NET Framework SDK在微軟官網可以下載,但現在好像包含在了.NET Framework Developer Pack(開發者包)里。https://www.microsoft.com/net/download。在這裡可以下載.NET Framework和.NET Core的最新版本及之前的版本。
如果不想那麼麻煩,可以直接安裝Visual Studio,.NET Framework SDK(或Developer Pack)是自動隨著IDE的安裝而安裝的。可以在這裡下載免費的Visual Studio 2017社區版:https://visualstudio.microsoft.com/zh-hans/downloads/,也可以在這個頁面下方選擇安裝之前的舊版本。
安裝好SDK後,在磁碟中會多出很多.NET開發工具,其中一些工具需要在命令提示符中打開(Command,CMD)。但這些工具分散在各個文件夾下,需要為它們配置PATH環境變數,這樣很麻煩。在安裝好Visual Studio後,磁碟中會多出一個類似於CMD的命令提示符,叫作Developer Command Prompt for VS + VS的版本號。Developer Command Prompt預先配置了每一個.NET開發工具,不需要為它們註冊PATH路徑,就可以在這裡直接使用了。
比如這裡,輸入csc -?,視窗中顯示了C#編譯器的命令行參數列表;同樣地,輸入vbc -?,視窗顯示VB編譯器的命令行參數列表。其中,有些參數在我們用csc.exe編譯C#源文件時會用到。
一、編輯源程式
在C盤新建一個文件夾test,在文件夾里創建一個記事本文件HelloWorld.txt。用記事本打開編輯這個文件,輸入C#代碼,註意輸入空格以縮進。之後將HelloWorld.txt尾碼名改為HelloWorld.cs。*.cs是C#代碼文件的尾碼名。
二、打開Developer Command Prompt,啟動csc.exe編譯源程式
更換路徑到源程式所在文件夾下。
輸入csc HelloWorld.cs,啟動編譯。
編譯成功,在test文件夾下,可以看到HelloWorld.cs已經被編譯成一個可執行程式HelloWorld.exe。
三、C#編譯器(csc.exe)的輸出選項
前面已經實現了用記事本編輯C#源程式並用csc.exe編譯,最後在文件夾下可以成功打開編譯而來的可執行程式。現在,考慮編譯過程中的一些細節。
源程式叫作HelloWorld.cs,編譯後的程式叫作HelloWorld.exe。看上去沒什麼問題,其實編譯後的程式的名字和類型是可以通過C#編譯器的輸出選項(參數)指定的。
①/out 規定編譯後文件名字,如果不進行設置,編譯後文件名與源程式名字相同 ②/target:exe 編譯源程式成可執行的控制台程式,預設選項 ③/target:library 編譯源程式成*.dll程式集 ④/target:winexe 編譯源程式成窗體程式 (其中/target可縮寫成/t)
所以之前在編譯時,我們輸入:csc HelloWorld.cs其實等價於輸入:csc /target:exe /out:HelloWorld.exe HelloWorld.cs,只是中間兩個選項都省略掉了。命令行選項和源文件的順序是任意的,可以命令行選項在前,源文件在後。也可以源文件在前,命令行選項在後,甚至可以這樣寫:csc /target:exe HelloWorld.cs /out:HelloWorld.exe,這些都是可以的。
打開Developer Command Prompt,進行其他選項的測試。
此外,命令行輸出選項中的"/"符號還可以換成"-"符號。
四、源程式中引用了外部程式集
修改源文件。using System.Windows.Forms引入了一個命名空間,以使用其中的MessageBox類的靜態方法Show(),彈出一個對話框顯示相關內容。System.Windows.Forms命名空間存在於System.Windows.Forms.dll程式集中(命名空間與程式集名稱相同)。源文件中使用了外部程式集的內容,csc.exe在編譯時需要通過/reference命令行選項指定引用的外部程式集(/reference可縮寫為/r)。
下麵進行編譯,省略/target和/out選項。
可能有讀者在這裡並沒有/reference:System.Windows.Forms,而是直接csc HelloWorld.cs,也可以成功編譯並運行,在後文會對這個問題進行解答。(C#預設響應文件csc.rsp的概念)
這裡還有一個問題,在源文件中,使用System.Windows.Forms命名空間中的MessageBox類,需要引入這個命名空間所在的程式集System.Windows.Forms.dll,那使用System命名空間中的Console類,為什麼不引入System命名空間所在的程式集System.dll?
這就涉及到了“外部程式集”中“外部”的概念。在Visual Studio中,引入System.Windows.Forms.dll程式集後,查看其包含的內容。可以看到Show()方法是MessageBox類的靜態方法,MessageBox類是System.Windows.Forms命名空間中的成員,而這個命名空間又是System.Windows.Forms.dll程式集中的邏輯概念。下圖中,左側兩個小黑方塊中間用一杠連起來的那個符號就是程式集的符號,花括弧的那個符號是命名空間的意思。
System.Windows.Forms.dll是外部程式集,那什麼又叫作“不是外部程式集”呢?查看System.dll程式集中的System命名空間的成員,發現並沒有我們使用的Console類。
這是因為,我們使用的Console.WriteLine()中的Console類所在的命名空間System,不是包含在System.dll中的!我們查看mscorlib這個程式集。
Console類原來是mscorlib.dll程式集中System命名空間的成員。mscorlib(MicroSoft CORe LIBrary),相對於System.Windows.Forms等一些外部程式集來說,是.NET平臺中核心的程式集,可以把它們理解成“內部的”程式集。所以回到之前的那個問題,使用mscorlib.dll程式集中命名空間中的成員,只要在源文件中使用using關鍵字引入所用成員所在的命名空間即可(也可使用成員的完全限定名),而不用在使用csc.exe編譯時通過/reference命令行選項額外引入mscorlib.dll這個程式集。
其實,在Visual Studio IDE里看這個問題,也是相通的。在我們新建了一個控制台應用程式後,在解決方案管理器中References下會自動引入一些外部程式集。(mscorlib不顯示在其中,因為它不需要引入!)當需要使用MessageBox等一些沒有自動被引入的外部程式集中的成員時,就需要我們手動右鍵References添加所用的程式集。而mscorlib.dll是在創建應用程式時就已經添加進來的程式集,不用額外引入。在IDE中是這樣,在命令行提示符中使用csc.exe編譯時也是這樣。
在Visual Studio中可以看到程式集在磁碟中的路徑。
在Visual Studio中創建應用程式時會選擇.NET Framework的版本,因為例子中這個程式選擇的是.NET Framework 4.6.1,所以它引用的程式集就是磁碟中.NET Framework 4.6.1中的程式集。
進入這個文件夾,可以看到其中包含的程式集。我們看到mscorlib.dll這個程式集的容量很大,也反映出這個程式集的重要性。
如果csc.exe需要引入多個外部程式集,在/reference:程式集1;程式集2 中用英文分號";"分隔即可。
五、編譯多個源文件
現在我們已經可以使用csc.exe和記事本構建一個可以引用外部程式集的控制台應用程式了,但是我們所有的代碼都是寫在一個C#源文件中的。我們也可以將代碼寫在多個文件中,使用csc.exe對多個源文件進行編譯。
在test文件夾下增加MyMessageBox.txt文件,之後要將尾碼名改為.cs(下同)。
修改HelloWorld.txt文件。
打開Developer Command Prompt,編譯這兩個文件,註意依然要使用/reference引入使用的外部程式集。編譯的多個文件之間用空格隔開。
執行這個程式。
此外,在使用csc.exe編譯多個文件時,還可以使用通配符"*"表示編譯當前目錄下的所有指定尾碼名文件。如:csc *.cs表示編譯當前目錄下所有.cs文件。
六、使用C#響應文件
至此,我們已經可以使用csc.exe編譯多個源文件的C#應用程式了。在編譯過程中,需要設置一些命令行選項以達到某種效果。當程式規模大到一定程度,就需要輸入很多的命令行選項,容易出錯且錄入工作量大。為了應對這一問題,C#有響應文件(response file,尾碼名為rsp)的概念。C#響應文件包含編譯一個或多個C#源文件時需要指定的命令行選項。
編輯HelloWorld.rsp文件,將編譯源文件時需要用到的引入外部程式集、設置輸出程式的類型及名字等命令行選項寫在這個文件里,並將這個響應文件和源程式文件放在同一目錄下。csc.exe編譯時,輸入csc @HelloWorld.rsp就可以按照設置的命令行選項編譯這個C#源程式了。
程式可以正常運行。
這裡有幾點需要註意的地方:①寫在後面的命令行選項或響應文件的內容會覆蓋掉前面的命令行選項或響應文件的內容(以後規定的為準!) ②/reference具有累加性,最終程式引用的外部程式集為各個地方(命令行選項和響應文件)規定的程式集的並集
七、關於C#預設的響應文件csc.rsp
回到之前提到的那個問題,為什麼即使沒有使用/reference引入需要的外部程式集,程式也是可以成功編譯並執行的?
C#編譯器(csc.exe)有一個與之關聯的預設響應文件(csc.rsp),csc.rsp與csc.exe在同一目錄下(我沒有找到..)。在編譯C#源程式時,無論有沒有自己編寫的響應文件,這個預設的響應文件csc.rsp都會執行。而csc.rsp已經寫好了對很多核心程式集的引用(用/reference或/r命令行選項)。所以即使我們沒有使用/reference引入外部程式集,csc.rsp也幫我們引入好了。
如果不想在編譯時自動執行csc.rsp,可以指定/noconfig選項。
如果我們在編譯時指定了/noconfig選項且沒有使用/reference引入源文件中需要的外部程式集,那麼編譯將報錯。
如果程式引用了在源文件中沒有用到的外部程式集(比如csc.rsp幫我們自動引入的),它們將會被編譯器忽略,所以不會影響程式的質量。