.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號:N160316901
出刊日期:2016/3/9
開發工具:Visual Studio 2015 Update 1
版本:.NET Framework 4.6、C# 6
在這篇文章之中,我將介紹Visual Studio 2015工具中獨立的範本專案 – 「Shared Project(共享專案)」。Shared Project可以讓你在不同類型的專案之中,例如主控台、WPF專案,共享程式碼。「Shared Project」最早是在Visual Studio 2013 Update 2版本中出現,現在已內建在Visual Studio 2015工具之中。
Shared Project(共享專案)支援以下類型的檔案,包含C#類別、HTML、XAML、JavaScript、圖片檔、資源檔、樣式表…等等。可以讓你在多種不同類型的專案之中,共享程式碼,如主控臺應用程式(Console)、WPF、Web應用程式,或Windows Universal Application。
在Shared Project(共享專案)之中,你可以搭配條件式編譯指示詞(Conditional compilation directives),如「#if」,為特定專案或平台來撰寫程式碼。
為了方便說明,我們來利用Visual Studio 2015工具,建立Shared Project(共享專案)來說明要如何使用它。
建立Shared Project(共享專案)
利用Visual Studio 2015來建立Shared Project(共享專案),從「File」-「New」-「Project」,在「New Project」對話盒中,確認視窗上方.NET Framework的目標版本為「.NET Framework 4.6」或以上,選取左方「Installed」-「Templates」-「Visual C#」程式語言,從「Windows」分類中,選取「Shared Project」,適當設定專案名稱與專案存放路徑,按下「OK」鍵,請參考下圖所示:

圖 1:建立Shared Project(共享專案)。
從Visual Studio 2015開發工具-「Solution Explorer」視窗- 「MyShared Project」專案上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「New Item」項目,開啟「Add New Item」對話盒,從右上方文字方塊輸入「Class」關鍵字搜尋,選取「Class」,設定類別名稱為「Utils」,然後按下「Add」按鈕,建立新類別,請參考下圖所示:

圖 2:建立新類別。
在類別之中,加入以下程式碼,利用條件式編譯指示詞(Conditional compilation directives)判斷語法,若在主控台應用程式中,使用到共享專案中的類別程式,則利用Console類別的WriteLine方法印出除錯訊息到主控台;若是在網站應用程式使用時,則使用Response.Write印出除錯訊息到網頁:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
namespace MySharedProject {
public class Utils {
public static void ShowMsg( string n ) {
#if MyConsole
Console.WriteLine("Hello " + n);
#elif MyWebApp
HttpContext.Current.Response.Write("Hello " + n);
#endif
}
}
}
加入主控台專案(Console Application)
使用Visual Studio 2015 建立主控台專案,從「Solution Explorer」視窗中,選取方案項目,按滑鼠右鍵,從快捷選單中,選取「Add」-「New Project」項目,從「Visual C#」分類中,選取「Console Application」項目,設定名稱為「MyConsoleApp」,然後按下「OK」按鈕,請參考下圖所示:

圖 3:加入主控台專案(Console Application)。
下一步,讓主控台類型程式參考Shared Project(共享專案)。在「Solution Explorer」視窗,選取「MyConsoleApp」專案,按滑鼠右鍵,從快捷選單選擇「Add」-「Reference」項目,勾選「Shared Project」分頁中的「MySharedProject」專案,這樣就可以在Console專案中引用Shared Project,請參考下圖所示:

圖 4:在Console專案中引用Shared Project。
然後我們在父專案(MyConsoleApp)加入程式碼,在Main方法中直接叫用MySharedProject.Utils.ShowMsg方法印出除錯訊息:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyConsoleApp {
class Program {
static void Main( string [ ] args ) {
MySharedProject.Utils.ShowMsg( "Mary" );
}
}
}
接著在主控台專案中,自定一個條件式編譯指示詞(Conditional compilation directives)。雙擊方案總管「MyConsoleApp」專案下方的「Properties」節點,開啟專案屬性頁面。在「Build」分頁中,設定「Conditional compilation symbols」的值為「MyConsole」,而MySharedProject專案屬性頁則不必做任何的設定,請參考下圖所示:

圖 5:自定一個條件式編譯指示詞(Conditional compilation directives)。
按CTRL + F5執行主控台應用程式,則主控台將印出除錯訊息,請參考下圖所示:

圖 6:主控台印出除錯訊息。
乍看之下,Shared Project(共享專案)與Class Library(類別庫)專案非常的相像,不過實際上運作的方式完全不同。Shared Project用來共享原始程式碼(Source Code),而類別庫用來共用編譯過的組件(Assembly)。使用ildasm.exe工具檢視MyConsoleApp專案產生出的組件資訊,你將會發現Shared Project(共享專案)在編譯時,會將專案中的內容編譯成為主控台專案的一部分,請參考下圖所示:

圖 7:MyConsoleApp專案產生出的組件資訊。
因此當你開啟主控台專案的csproj檔案,可以看到檔案中包含一個<Import>標籤,這表示編譯主控台專案時,會將Shared Project(共享專案)匯入專案之中:
<Import Project="..\MySharedProject\MySharedProject.projitems" Label="Shared" />
因為將Shared Project(共享專案)當作是在MyConsoleApp專案的一部分,因此只需要在MyConsoleApp專案的屬性頁設定「MyConsole」除錯符號,而MySharedProject專案則不必設定。
參考類別庫專案
和Shared Project不同的是,類別庫專案(Class Library)以外部組件的方式,編譯成dll檔案,被主控台專案中引用,讓我們在方案中加入一個類別庫專案做測試。從「Solution Explorer」視窗中,選取方案項目,按滑鼠右鍵,從快捷選單中,選取「Add」-「New Project」,從「Visual C#」分類中,選取「Class Library」項目,設定名稱為「MyClassLibrary」,然後按下「OK」按鈕,請參考下圖所示:

圖 8:參考類別庫專案。
若開啟MyConsoleApp主控台專案的csproj檔案,可以看到其中包含一個<ProjectReference>的設定:
<ProjectReference Include="..\MyClassLibrary\MyClassLibrary.csproj">
<Project>{a613933f-73e5-4297-b31f-de47082ad65f}</Project>
<Name>MyClassLibrary</Name>
</ProjectReference>
因為MyClassLibrary專案中的程式會使用到HttpContext類別,因此在MyClassLibrary專案中要加入System.Web.dll組件的參考。在「Solution Explorer」視窗,選取「MyClassLibrary」專案,按滑鼠右鍵,從快捷選單選擇「Add」-「Reference」項目,勾選「Assemblies」分頁中的「System.Web」組件,請參考下圖所示:

圖 9:引用System.Web.dll組件的參考。
在類別庫專案預設的Class1.cs檔案之中,加入以下程式碼,定義MyClassUtils類別,撰寫ShowMsg方法,利用Response.Write印出除錯訊息:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace MyClassLibrary {
public class MyClassUtils {
public static void ShowMsg( string n ) {
#if MyConsole
Console.WriteLine("Hello " + n);
#elif MyWebApp
HttpContext.Current.Response.Write( "Hello " + n );
#endif
}
}
}
最後設定MyConsoleApp主控台程式參考MyClassLibrary專案,在「Solution Explorer」視窗,選取「MyConsoleApp」專案,按滑鼠右鍵,從快捷選單選擇「Add」-「Reference」項目,勾選「Projects」-「Sloution」分頁中的「MyClassLibrary」專案,這樣就可以在Console專案中引用類別庫,請參考下圖所示:

圖 10:在Console專案中引用類別庫。
修改MyConsoleApp專案中的 Main方法,叫用MyClassLibrary.MyClassUtils.ShowMsg來印出除錯訊息:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyConsoleApp {
class Program {
static void Main( string [ ] args ) {
MySharedProject.Utils.ShowMsg( "Mary" );
MyClassLibrary.MyClassUtils.ShowMsg("candy" );
}
}
}
按CTRL + F5執行MyConsoleApp專案,這次只有印出MySharedProject.Utils.ShowMsg這行程式碼印出訊息,而MyClassLibrary.MyClassUtils.ShowMsg這段程式碼沒有印出除錯訊息,請參考下圖所示:

圖 11:測試叫用類別庫組件程式的結果。
使用ildasm.exe工具檢視MyConsoleApp.exe組件資訊,MyClassLibrary類別庫專案被視為是外部組件,請參考下圖所示:

圖 12:類別庫專案被視為外部組件。
正是因為類別庫專案並沒有定義條件式編譯符號「MyConsole」的關係,MyClassUtils. ShowMsg方法的訊息不會印出到主控台,讓我們為MyClassLibrary專案定義條件式編譯符號,雙擊方案總管「MyClassLibrary」專案下方的「Properties」節點,開啟專案屬性頁面。在「Build」分頁中,設定「Conditional compilation symbols」的值為「MyConsole」,請參考下圖所示:

圖 13:為MyClassLibrary專案定義條件式編譯符號。
這樣執行MyConsoleApp程式時,MyClassUtils. ShowMsg方法的訊息才會印出到主控台,請參考下圖所示:

圖 14:測試叫用類別庫組件程式的結果。
在Web應用程式專案中使用Shared Project(共享專案)
最後,我們來探討一下在Web應用程式的專案中該如何使用Shared Project(共享專案),從「Solution Explorer」視窗中,選取方案項目,按滑鼠右鍵,從快捷選單中,選取「Add」-「New Project」項目,從「File」-「New」-「Project」項目,在「New Project」對話盒中,,選取左方「Installed」-「Templates」-「Visual C#」程式語言,從「Web」分類中,選取「ASP.NET Web Application」,設定專案名稱為「MyWebApplication」,以及專案存放路徑,並按下「OK」鍵。請參考下圖所示:

圖 15:加入Web應用程式的專案。
在「New ASP.NET Project」對話盒中選取「Empty」項目,勾選下方的「Web Forms」項目,然後按下「OK」按鈕建立專案,請參考下圖所示:

圖 16:建立空白Web Forms專案。
而在Web Application類型的專案中,使用Add Reference功能時,並無「Shared Project」分頁,因此沒法參考到Shared Project(共享專案),請參考下圖所示:

圖 17:預設Web Application類型的專案無法參考共享專案。
解法方案如下,先使用「Unload Project」功能將Web Applictaion從方案暫時移除,選取「Solution Explorer」視窗中的「MyWebApplication」專案,按滑鼠右鍵,從快捷選單中選取「Unload Project」項目,請參考下圖所示:

圖 18:「Unload Project」功能。
選取「Solution Explorer」視窗中的「MyWebApplication」專案,按滑鼠右鍵,從快捷選單中選取「Edit MyWebApplication.csproj」項目,編輯專案檔案,請參考下圖所示:

圖 19:編輯專案檔案。
修改<ProjectTypeGuids>項目,預設Web Application類型的專案,應該會看到以下的設定,包含兩個ID:
<ProjectTypeGuids>
{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
</ProjectTypeGuids>
第一個項目是Web Application的ID,第二個項目描述的是C#專案,先移除第一個ID,修改設定如下:
<ProjectTypeGuids> {fae04ec0-301f-11d3-bf4b-00c04f79efbc} </ProjectTypeGuids>
儲存專案檔案,接著重新載入編輯過的專案,選取「Solution Explorer」視窗中的「MyWebApplication」專案,按滑鼠右鍵,從快捷選單中選取「Reload Project」項目,請參考下圖所示:

圖 20:「Reload Project」項目。
此時便可以選取「Solution Explorer」視窗的「MyWebApplication」專案,按滑鼠右鍵,從快捷選單中選取「Add Referece」項目,「Reference Manager」對話盒中就會出現「Shared Project」分頁,讓專案能夠參考到 Shared Project(共享專案),請參考下圖所示:

圖 21:參考 Shared Project(共享專案)。
完成參考動作之後,「Solution Explorer」視窗的「MyWebApplication」專案下,「References」項目下就會多出一個MySharedProject節點,請參考下圖所示:

圖 22:引用「Shared Project」。
接著照前面的步驟,使用「Unload Project」功能,將<ProjectTypeGuids>項目的設定改回來,選取「Solution Explorer」視窗中的「MyWebApplication」專案,按滑鼠右鍵,從快捷選單中選取「Unload Project」項目,修改設定如下:
<ProjectTypeGuids>
{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
</ProjectTypeGuids>
完成參考動作之後,那麼就可以在Web應用程式專案中,使用到Shared Project(共享專案),先加入一個Web Form測試,選取「Solution Explorer」視窗中的「MyWebApplication」專案,按滑鼠右鍵,從快捷選單中選取「Add」-「New Item」項目,然後選取「Web Form」,取一個名稱,然後按下「Add」按鈕,請參考下圖所示:

圖 23:加入「Web Form」項目。
雙擊ASPX設計畫面,進入程式設計視窗,在Page_Load事件處理常式中,加入以下程式碼,叫用MySharedProject.Utils.ShowMsg("Mary" )印出訊息到瀏覽器:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace MyWebApplication {
public partial class WebForm1 : System.Web.UI.Page {
protected void Page_Load( object sender , EventArgs e ) {
MySharedProject.Utils.ShowMsg("Mary" );
}
}
}
執行之前,要設定條件式編譯指示詞(Conditional compilation directives)。雙擊方案總管「MyWebApplication」專案下方的「Properties」節點,開啟專案屬性頁面。在「Build」分頁中,設定Conditional compilation symbols的值為「MyWebApp」,請參考下圖所示:

圖 24:設定條件式編譯除錯符號。
選取「Solution Explorer」視窗中的ASPX檔案,按滑鼠右鍵,從快捷選單中選取「View In Browser」項目,執行網頁,執行結果請參考下圖所示:

圖 25:網頁測試結果。
類別庫與Shared Project(共享專案)
最後總結一下類別庫與Shared Project(共享專案)的差異:
類別庫:
- 共享組件
- 編譯成一個組件。
- 只能包含C#程式 (若Visual Basic類型的專案,則只能包含Visual Basic程式)
Shared Project(共享專案):
- 共享原始程式碼與資源檔
- 可以包含C#程式、XAML檔案、JavaScript檔案…等共用的資源。
- 可以在多種類型的專案中使用Shared Project,包含:Console、Windows Forms、WPF、Web Application、Universal App..等等。
- 不會編譯成一個組件,它將編譯成父專案的一部份。
- 可以使用條件式編譯指示詞(Conditional compilation directives),以撰寫特定平台所需的程式碼。