型別等價 (Type Equivalence) 是 .NET Framework 4.0 引入的新功能,它的作用是將型別的符號匯入到目標的組件中,讓來源的組件就算是版本變更了,其用戶端程式也可以在不用編譯的情況下仍可正常執行,這個功能是做給 COM 元件用的,它可以讓用戶端程式直接匯入 COM 型別函式庫,並且不用再多部署 COM 型別函式庫即可直接呼叫 COM DLL 或元件,不過若是 Managed code,仍然可以使用這個功能。不過,由於這個功能是給 COM 元件使用的 (.NET 元件不入用 [ComImport] 來開放介面),所以在 Managed Code 上用效益並不明顯,若沒有用到 COM 元件的話,這個功能其實不用在意太多。
若要做到 Managed Code 的型別等價,元件端必須要具備下列條件:
1. 至少開放一個介面。
2. 在介面中使用 [ComImport] 來宣告,並且設定介面的 Guid 值。
3. 在組件的資訊檔中,使用 [assembly: ImportFromTypeLib(“”)] 設定,並且也要設定組件層級的 GUID 值 (這是目前 Visual Basic 和 C# 預設就會有的功能)。
在滿足上述條件以後,於用戶端專案在要使用型別等價的元件上,設定 Embed Interop Type 為 true (在屬性視窗),如此可以將型別等價的介面內嵌到用戶端應用程式中,如此就算是實作它的元件 (runtime component) 發生變化,用戶端程式也無需再次編譯即可正常執行,也就是說,就算 runtime component 不同 (例如 Office 2003/2007),只要型別等價的介面是相同的話,用戶端仍可以正常執行。不過實作型別等價的程序有一點複雜,以下簡單說明如何建構簡單的型別等價程式:
A. 建立一個要作為型別等價介面的元件類別庫專案,命名為 TypeEquivalenceInterface,然後設定其專案輸出到一個指定的位置 (可以是方案目錄內的一個新子目錄,例如 \Binaries):
B. 接著,將原本的 Class1.cs,更名為 ISampleInterface.cs,其內部宣告也會自動變為 class ISampleInterface,請將 class 改為 interface,並加入 [ComImport] 以及 [Guid] 屬性,例如下列程式所示:
using System.Runtime.InteropServices;
namespace TypeEquivalenceInterface
{
[ComImport]
[Guid("B4D28905-DCA2-4B1E-864A-A96AC967D084")]
public interface ISampleInterface
{
string VersionData { get; }
int GetDataV1();
}
}
在上面的範例中,Guid 請變更為一組新的,讀者可以利用 Visual Studio 的 Tools/Generate GUID 工具來產生新的 GUID,然後將原本的替換掉。
C. 在專案中打開 Properties/AssemblyInfo.cs,並加入下列的指令,然後建置它:
[assembly: ImportFromTypeLib(“”)]
D. 新增一個要實作型別等價介面的類別庫,命名為 TypeEquivalenceImpl,與前一個元件一樣,設定輸出路徑到相同的位置後,加入 TypeEquivalenceInterface 元件的參考 (請注意:要由輸出目錄去加,不能使用加入專案方式)。然後在加入的 TypeEquivalenceInterface 元件的參考屬性中,設定 Specify version 為 FALSE:
E. 更名 Class1.cs 為 SampleClass.cs,然後以下列程式碼作為實作碼,並建置它。
namespace TypeEquivalenceImpl
{
public class SampleClass : TypeEquivalenceInterface.ISampleInterface
{
public string VersionData { get { return "version 1 stamp."; } }
public int GetDataV1()
{
return 121;
}
}
}
F. 新增用戶端程式 (主控台應用程式),命名為 TypeEquivalenceClient,並如同前一個專案般設定相同的輸出路徑,然後在輸出路徑中加入 TypeEquivalenceInterface.dll 的參考 (不必加 TypeEquivalenceImpl.dll),並且將 TypeEquivalenceInterface 的參考屬性中的 Embed Interop Type 為 TRUE:
G. 使用下列程式碼作為用戶端程式,並按 CTRL+F5,可以看到這樣的畫面:
namespace TypeEquivalenceClient
{
class Program
{
static void Main(string[] args)
{
Assembly runtimeLibrary = Assembly.Load("TypeEquivalenceImpl");
ISampleInterface sampleClass =
(ISampleInterface)runtimeLibrary.CreateInstance("TypeEquivalenceImpl.SampleClass");
Console.WriteLine("version data: " + sampleClass.VersionData);
Console.WriteLine("GetDataV1(): " + sampleClass.GetDataV1());
sampleClass = null;
Console.ReadLine();
}
}
}
至此,整個架構就完成了。
H. 請修改 TypeEquivalenceInterface,將版本號改為 2.0.0.0,並且在程式中加入一個成員:
using System.Runtime.InteropServices;
namespace TypeEquivalenceInterface
{
[ComImport]
[Guid("B4D28905-DCA2-4B1E-864A-A96AC967D084")]
public interface ISampleInterface
{
string VersionData { get; }
int GetDataV1();
int GetDataV2();
}
}
並且配合修改 TypeEquivalenceImpl 以增加實作,並且一樣將它的版本號改為 2.0.0.0:
namespace TypeEquivalenceImpl
{
public class SampleClass : TypeEquivalenceInterface.ISampleInterface
{
public string VersionData { get { return "version 1 stamp."; } }
public int GetDataV1()
{
return 121;
}
public int GetDataV2()
{
return 250;
}
}
}
然後編譯 TypeEquivalenceInterface 以及 TypeEquivalenceImpl,但是不要建置 TypeEquivalenceClient,直接到輸出目錄執行 TypeEquivalenceClient,你會發現程式仍可正常執行不受影響。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/9915070/viewspace-666903/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/9915070/viewspace-666903/