Windows 執行階段 (WinRT) 類型系統
一般注意事項
除了基本類型以外,所有類型都必須包含在命名空間內。 型別在全域命名空間中無效。
Windows所提供的類型全都包含在Windows.*命名空間下。 未由Windows (提供的 WinRT 類型,包括 Microsoft) 其他部分所提供的 WinRT 類型,必須存在於Windows.*以外的命名空間中。
除了介面之外,所有 WinRT 類型都必須具有公開可見度。 WinRT 介面可能會選擇性地具有私人可見度。 所有其他使用者定義的 WinRT 類型 (結構、類別、列舉、委派、屬性) 必須具有公開可見度。
WinRT 不支援巢狀類型。 沒有 WinRT 類型可以封入另一種類型;無法將 WinRT 類型巢狀置於另一個類型內。
不是 WinRT 類型系統的所有層面都可供您作為協力廠商開發人員使用。
WinRT 支援介面和委派的參數化。 不過,在此版本中,WinRT 不支援協力廠商的參數化型別定義。 僅支援Windows.* 命名空間中系統中所包含的參數化型別。
WinRT 支援類別組合作為執行時間繼承機制。 不過,在此版本中,WinRT 不支援根可撰寫類別的定義。 僅支援Windows.*命名空間中系統中所包含的根可撰寫類別。
WinRT 命名空間和類型名稱會保留大小寫,但不區分大小寫,類似于Windows檔案系統和Windows登錄。 這表示您無法有只依大小寫而有所不同的命名空間或類型名稱。 例如,您無法同時擁有 Foo.SomeType 和 foo。AnotherType,也無法同時擁有 Foo.SomeType 和 Foo.someType。
WinRT 識別碼必須符合下列文法。 請注意,僅支援 Unicode 3.0 和更早版本中定義的字元。
identifier-or-keyword:
identifier-start-character identifier-continuation-characters*
identifier-start-character:
letter-character
underscore (U+005F)
identifier-continuation-characters:
identifier-continuation-character
identifier-continuation-characters identifier-continuation-character
identifier-continuation-character:
identifier-start-character
decimal-digit-character
connecting-character
combining-character
formatting-character
letter-character:
A Unicode 3.0 character of classes Lu, Ll, Lt, Lm, Lo, or Nl
combining-character:
A Unicode 3.0 character of classes Mn or Mc
decimal-digit-character:
A Unicode 3.0 character of the class Nd
connecting-character:
A Unicode 3.0 character of the class Pc
formatting-character:
Zero Width Non-Joiner (U+200C)
Zero Width Joiner (U+200D)
參數化型別
WinRT 支援介面和委派的類型參數化。 參數化型別允許定義一系列介面,這些介面可以在支援參數多型的程式設計語言中以多型方式處理。
參數化型別具現化會在型別內容中使用型別的引數清單指定時發生,例如方法參數位置。 例如, HRESULT foo(X<Y> x)
具現 化 X 所 命名的參數化型別,其類型 為 Y 做為其第一個且唯一的類型引數。
未參數化的 WinRT 介面或委派會指派 GUID,以唯一識別基礎介面與相同物件上的其他介面不同。 例如,參數化介面 (例如, IVector<T>
) 或委派 (, EventHandler<T>
) 會改為指派參數化介面識別碼 (PIID) ,這是可唯一識別此參數化型別的 GUID。 這不是 IID。 此 GUID 用於產生參數化型別實例的 IID,例如 () IVector<int>
。
參數化型別引數清單
這些 WinRT 類型可以出現在參數化型別的引數清單中。
- WinRT 基本類型 (例如 Boolean、 Int32、 String、 Guid等)
- WinRT 列舉
- WinRT 結構
- WinRT 介面
- WinRT 委派
- WinRT 執行時間類別
- 例如,其他參數化型別具現化 (,
IVector<IVector<int>>
) 禁止任何其他類型出現在參數化型別引數清單中。 例如,陣列。
參數化型別實例
參數化型別實例可以出現在非參數化型別可以出現的任何內容中。 參數化介面實例可以在介面可使用的任何位置使用,例如執行時間類別所實作的介面清單中。 參數化委派實例可以在委派使用的任何位置使用,例如在事件的定義中。
參數化型別參數可以出現在參數化介面或委派定義中;或者,一般類型可以正常出現的任何位置。 如果只有介面出現的參數,該參數會限制為介面。 如果參數出現在任何類型可以出現的內容中,則不會限制該參數;依此類推。 參數化型別實例的引數必須符合所有這類限制。
參數化型別的 Guid 產生
GUID 產生演算法必須符合這些需求。
- 使用相同引數將參數化型別具現化兩次時,必須將兩個具現化指派給相同的介面或委派主體,以及相同的 IID。
- 如果具現化兩個不同的參數化型別,即使具有相同的引數,也必須統計上不太可能指派相同的 IID。
- 如果參數化型別具現化兩次,但使用不同的引數,則這兩個具現化不太可能指派相同的 IID。
注意
不允許參數化型別使用與引數相同的具現化來具現化,或做為出現在引數清單中的任何其他參數化型別的引數, (即迴圈具現化) 。 例如,如果 X = Foo<Y>
違反 、 和 Y = Foo<X>
,則為非迴圈性。 不過,如果 X = Foo<Y>
和 Y = Foo<int>
,則已維護非迴圈性。
具現化演算法如下所示。
- 每個參數化型別都會由其作者指派參數化介面識別碼,也就是縮寫的 PIID。 請注意,PIID 不是 IID,也不會當做引數傳遞至 QueryInterface。 作者必須確定 PIID 對參數化型別而言是唯一的。
- 基底類型的類型簽章是 ASCII 八位字串, (請參閱下表) 。 例如, Int32 是 「i4」。
- 不是參數化介面實例之介面的類型簽章是以破折號形式以 ASCII 編碼的 IID,並以大括弧分隔。 例如,"{00000000-0000-0000-0000-000000000000}"。
- 不是參數化委派實例的委派類型簽章是字串 「delegate」,然後是 IID 作為介面。 詳細文法隨即出現。
- 參數化型別的 GUID 會根據這個文法計算。
- 根據 UUID rfc 4122,計算 5 sha-1 產生的signature_octets雜湊—這會使用單一 winrt pinterface/pintergroup guid 作為命名空間,如 rfc 4122/4.3 中所述,以及 pinterface/pintergroup 的簽章,以及其具現化為名稱字串的引數。
- pinterface 具現化會指派此 guid,以及 4 的簽章。
signature_octets => guid_to_octets(wrt_pinterface_namespace) string_to_utf8_octets(ptype_instance_signature)
wrt_pinterface_namespace => "11f47ad5-7b73-42c0-abae-878b1e16adee"
ptype_instance_signature => pinterface_instance_signature | pdelegate_instance_ signature
pinterface_instance _signature => "pinterface(" piid_guid ";" args ")"
pdelegate_instance _signature => "pinterface(" piid_guid ";" args ")"
piid_guid => guid
args => arg | arg ";" args
arg => type_signature
type_signature => base_type_identifer | com_interface_signature | interface _signature | delegate_signature | interface_group_signature | runtime_class_signature | struct_signature | enum_signature | pinterface_instance_signature | pdelegate_instance_signature
com_interface_signature => "cinterface(IInspectable)"
base_type_identifier is defined below
interface_signature => guid
interface_group_signature => "ig(" interface_group_name ";" default_interface ")"
runtime_class_signature => "rc(" runtime_class_name ";" default_interface ")"
default_interface => type_signature
struct_signature => "struct(" struct_name ";" args ")"
enum_signature => "enum(" enum_name ";" enum_underlying_type ")"
enum_underlying_type => type_signature
delegate_signature => "delegate(" guid ")"
guid => "{" dashed_hex "}"
dashed_hex is the format that uuidgen writes in when passed no arguments.
dashed_hex => hex{8} "-" hex{4} "-" hex{4} "-" hex{4} "-" hex{12}
hex => [0-9a-f]
- 當 p 類型具現化當做引數傳遞至其他 pinterface 時,步驟 3 所計算的簽章會視需要作為文法元素 'pinterface_instance_signature' 或 'pdelegate_instance_signature' 中的類型簽章。
這些名稱會在出現時用於基底類型。
- UInt8 對應至 「u1」
- Int32 對應至 「i4」
- UInt32 對應至 「u4」
- Int64 對應至 「i8」
- UInt64 對應至 「u8」
- 單一 對應至 「f4」
- 雙精度 浮點數對應至 「f8」
- 布林值 對應至 「b1」
- 請注意,若要取得 布林 類型參數支援,您必須新增
/Yc:wchar_t
才能將 wchar_t 啟用為內建類型。
- 請注意,若要取得 布林 類型參數支援,您必須新增
- Char16 對應至 「c2」
- 字串 對應至 「string」
- Guid 對應至 「g16」
上述名稱區分大小寫。 除了 String之外,類型名稱會使用單一字元來建議資料類型,後面接著以位元組為單位的大小。 已選擇這些名稱:為簡潔 (以避免結構類型簽章) 的大小;表示看起來與 WinRT 名稱、RIDL 名稱或任何類型的語言投影名稱類似;和 仍然維持大致人類可讀性。
對於 enum_type_signature,唯一有效的 'underlying_type' 值是 Int32 或 UInt32的值。
對於 struct_type_signature,args 是結構欄位的type_signatures順序清單。 這些可能是基底類型或其他結構類型。
Struct_name和enum_name是命名空間限定的,使用句號 「.」 作為分隔符號。 例如,「namespace X { struct A{ int; }; }」 會變成 「struct (X.A;i4) 」。
Default_interface必須是使用 IDL '[default]' 屬性,在執行時間類別或介面群組主體中指定為預設值的介面、p 介面實例、委派或 p 委派實例。
請注意,會忽略自訂屬性;假設對封送處理沒有任何作用。
版本控制
基本類型以外的所有 WinRT 類型都必須有 Version 屬性。 語言投影會使用版本屬性資訊來啟用回溯相容性,以及針對啟動案例。 協力廠商類型必須包含 Version 屬性,但語言投影必須忽略它。 協力廠商 WinRT 元件會獨佔封裝在應用程式中,因此它們絕不可以獨立變更應用程式本身的版本。
Version 屬性可以選擇性地套用至介面成員, (方法、屬性和事件) 。 這適用于 C#/VB 和 C++/CX 中的高階類別撰寫。 介面成員上的版本屬性,即使是Windows系統介面成員,也必須在執行時間由語言投影忽略。
Version 屬性包含不帶正負號的 32 位整數建構函式參數。 對於 Windows WinRT 類型,此值是Windows相關聯類型建構的第一個定義版本 NTDDI 值。 對於協力廠商類型,此值的意義會由類型的作者決定。
Windows定義之後,系統結構、委派和介面都是不可變的。 任何後續Windows版本中都可能不會修改它們。
Windows系統列舉和執行時間類別可加總版本設定。 列舉可能會在後續Windows版本中新增列舉值。 類別可能會新增新的實作介面, (包括靜態、啟用處理站、組合處理站、可覆寫和受保護的介面,) 後續Windows版本中。 附加版本設定的進一步詳細資料會包含在列舉和執行時間類別的各節中。
命名空間
命名空間是用來組織程式碼的命名範圍,以及避免命名衝突。 WinRT 類型系統中的所有具名類型 (列舉、結構、委派、介面和執行時間類別) 在命名空間中。 命名空間可以包含其他命名空間。
基本類型
WinRT 類型系統包含一組核心內建基本類型。
WinRT 類型 | 類型描述 |
---|---|
Int16 | 16 位帶正負號的整數 |
Int32 | 32 位帶正負號的整數 |
Int64 | 64 位帶正負號的整數 |
UInt8 | 8 位不帶正負號的整數 |
UInt16 | 16 位不帶正負號的整數 |
UInt32 | 32 位不帶正負號的整數 |
UInt64 | 64 位不帶正負號的整數 |
Single | 32 位 IEEE 754 浮點數 |
Double | 64 位 IEEE 754 浮點數 |
Char16 | 代表 UTF-16 程式碼單位的 16 位非數值 |
Boolean | 8 位布林值 |
String | 用來表示文字的 Char16 不可變序列 |
Guid | 128 位標準 Guid |
列舉
「列舉型別」是含一組具名常數的相異實值型別。
每個列舉類型都有對應的整數型別,稱為列舉型別的基礎型別。 WinRT 中唯一合法的列舉基礎類型為 Int32 和 UInt32。
基礎類型為 UInt32 的列舉必須包含 FlagsAttribute。 基礎類型 為 Int32 的列舉不得包含 FlagsAttribute。
列舉必須具有公開可見度。
列舉版本控制
列舉可加法設定版本。 給定列舉的後續版本可能會 (也稱為具名常數) 的值。 預先存在的值可能不會移除或變更。 列舉值選擇性地包含 VersionAttribute,以區分何時將特定值新增至列舉類型。 沒有 VersionAttribute 的列舉值會被視為具有與封入列舉類型相同的版本值。
結構
結構是具有一或多個欄位的記錄類型。 結構一律會以傳值傳遞並傳回。 結構欄位只能是基本類型、列舉、結構、字串和IReference < T > (後者兩者是唯一兩個堆積配置的欄位類型) 。
結構必須具有公開可見度。
一般而言,結構至少必須有一個欄位 (有罕見的例外狀況,例如代表中繼資料合約的類型和屬性) 。 所有結構的欄位都必須是公用的。
結構不可為泛型或參數化。
介面
介面是由已定義其使用方式但未實作之相關型別成員群組所組成的合約。 介面定義會指定介面的成員—方法、屬性和事件。 沒有與介面相關聯的實作。
非參數化介面必須具有唯一的介面識別碼, (也稱為 IID) 透過 GuidAttribute 指定。 參數化介面必須具有唯一的參數化介面識別碼 (也稱為 PIID) 透過 GuidAttribute 指定的。 PIID 可用來透過上述指定的演算法,為特定的參數化介面實例產生 IID。
介面可能有公用或私人可見度。 這反映某些介面代表多個 WinRT 類別所實作的共用合約,而其他介面則代表由單一 WinRT 類別實作的成員。 私用可見度介面必須指定它透過 ExclusiveToAttribute 專屬的 WinRT 類別。 私人介面只能由 ExclusiveToAttribute 中指定的 WinRT 類別實作。
IInspectable 和 IUnknown
在介面方面,WinRT 沒有繼承的概念。 相反地, 介面可能需要另 一個介面。 如需詳細資訊,特別是 MIDL 3.0 requires
關鍵字,請參閱 MIDL 3.0 介面。
所有 WinRT 介面都會隱含地要求 IInspectable;接著 IInspectable 需要 IUnknown。 IUnknown 會根據傳統的 COM 使用方式定義三種方法:QueryInterface、AddRef 和 Release。 IInspectable 除了 IUnknown 方法之外,還會定義三個方法:GetIids、GetRuntimeClassName 和 GetTrustLevel。 這三種方法可讓物件的用戶端擷取物件的相關資訊。 特別是,IInspectable.GetRuntimeClassName 可讓物件的用戶端擷取可在中繼資料中解析的 WinRT 類型名稱,以啟用語言投影。
介面 需要
如上所述,介面可能會指定它 需要 一或多個其他介面,這些介面必須在實作有問題的介面的任何物件上實作。 例如,如果 IButton 需要 IControl,則實作 IButton 的任何類別也需要實作 IControl。
但 WinRT 類型系統或 ABI 都沒有介面繼承的概念。 因此,透過實作繼承自現有介面的新介面來新增新功能的概念 (例如 ,IFoo2 繼承自 IFoo) 沒有任何意義。 WinRT 語言投影可以使用繼承關聯性,以方便使用該特定語言的取用,而執行時間類別可以使用繼承,但是介面繼承不存在於 MIDL 3.0 撰寫的內容中 (請參閱 MIDL 3.0 介面) 。
參數化介面
介面支援類型參數化。 參數化介面定義除了介面成員和必要介面的清單之外,還會指定類型參數清單。 參數化介面的必要介面可能會共用相同的類型引數清單,例如,使用單一類型引數來指定介面的參數化實例,以及其需要 (的介面, IVector<T> requires IIterable<T>
例如,) 。 參數化介面的任何成員 (簽章、方法、屬性或事件) ,可能會從參數化介面的類型引數清單參考類型, IVector<T>.SetAt([in] UInt32 index, [in] T value)
例如 (,) 。
協力廠商無法定義新的參數化介面。 僅支援系統所定義的參數化介面。
委派
委派是作為型別安全函式指標的 WinRT 類型。 委派基本上是一個簡單的 WinRT 物件,會公開繼承自 IUnknown的單一介面,並定義名為 Invoke的單一方法。 叫用委派會接著叫用它所參考的方法。 委派通常是 (,但並非專門用來定義 WinRT 事件的) 。
WinRT 委派是具名類型,並定義方法簽章。 委派方法簽章遵循與介面方法相同的參數規則。 Invoke方法的簽章和參數名稱必須符合委派的定義。
與介面一樣,非參數化委派必須具有唯一的介面識別碼, (也稱為 IID) 透過 GuidAttribute 指定。 委派的 IID 是用來實作委派之單一方法介面的 IID。 參數化委派必須具有唯一的參數化介面識別碼, (也稱為透過 GuidAttribute 指定的 PIID) 。 PIID 是用來透過上述演算法產生特定參數化委派實例的 IID。
委派必須具有公開可見度。
IUnknown
請注意,不同于 WinRT 介面,委派會實作 IUnknown,但不會實 作 IInspectable。 這表示它們無法在執行時間檢查類型資訊。
參數化委派
委派支援類型參數化。 參數化委派定義除了如上所述的傳統方法簽章之外,還會指定類型參數清單。 在方法簽章中,任何參數都可以指定為參數化委派類型引數清單中的其中一個類型。
協力廠商無法定義新的參數化委派。 僅支援系統所定義的參數化委派。
介面成員
WinRT 介面支援三種類型的成員:方法、屬性和事件。 介面可能沒有資料欄位。
方法
WinRT 介面支援接受零個或多個參數的方法,並傳回 HRESULT ,指出方法呼叫成功或失敗。 方法可以選擇性地指出要投影為例外狀況語言傳回值的單一 out 參數。 如果指定,這個傳回值 out 參數必須是方法簽章中的最後一個參數。
方法必須具有公開可見度。
方法可能不會使用引數的變數編號。 方法可能沒有選擇性參數,或具有預設值的參數。
方法可能無法參數化。 參數化介面的參數化委派和方法可能會使用方法簽章中包含型別的類型參數。
參數
除了陣列長度參數以外的所有方法參數, (以下所述) 必須具有名稱和類型。 請注意,傳回值必須指定名稱,就像參數一樣。 方法參數名稱,包括傳回型別名稱,在方法的範圍內必須是唯一的。
只有參數化委派的參數和參數化介面的成員可以指定參數類型的參數化型別。 方法可能不會個別參數化。 例如,參數一律可以指定參數化型別實例 (, IVector<int>
) 做為參數類型。
所有方法參數都必須是獨佔或輸出參數。 不支援 In/out 參數。
雖然 WinRT 介面上的方法必須傳回 HRESULT,但方法可能會選擇性地指出其最終輸出參數是要當方法投影為例外狀況型語言時做為傳回值。 這類參數在用來宣告這些參數的 MIDL 語法之後稱為 [out, retval] 參數。 指定 [out, retval] 參數時,它必須是方法簽章中的最後一個參數。
除了 [out, retval] 需要出現在參數清單結尾之外,out 參數沒有其他排序需求。
陣列參數
WinRT 方法支援一致性陣列參數。 陣列永遠不能使用,但做為參數除外。 它們不能是獨立的具名型別,也無法當做結構欄位類型使用。 陣列參數可以當做 in
、 out
和 retval
參數使用。
WinRT 支援大部分 WinRT 類型的陣列參數,包括基本類型 (包括字串和 guid) 、結構、列舉、委派、介面和執行時間類別。 不允許其他陣列的陣列。
由於這些參數符合規範,陣列參數必須一律緊接在參數清單中,且陣列大小為 參數。 陣列大小參數必須是 UInt32。 陣列大小參數沒有名稱。
WinRT 支援三種不同的陣列傳遞樣式。
- PassArray。 當呼叫端提供 方法的陣列時,會使用此樣式。 在此樣式中,陣列大小參數和陣列參數都是兩個
in
參數。 - FillArray。 當呼叫端提供陣列給方法填滿時,最多會使用這個樣式。陣列大小上限。 在此樣式中,陣列大小參數是
in
參數,而陣列參數是out
參數。 使用 FillArray 樣式時,陣列參數可以選擇性地將其中一個其他參數指定為數組長度參數。 詳細資料如下。 - ReceiveArray。 當呼叫端收到 方法所配置的陣列時,會使用此樣式。 在此樣式中,陣列大小參數和陣列參數都是兩個
out
參數。 此外,陣列參數會以傳址方式傳遞 (,也就是 ArrayType**,而不是 ArrayType*) 。
注意
陣列大小參數的組合 out
,但 in
陣列參數在 WinRT 中無效。
當陣列參數當做 [out, retval] 參數使用時,陣列長度參數必須是 out
參數,也就是說,陣列只有 ReceiveArray 樣式是陣列合法的 retval
。
陣列長度參數
FillArray 樣式陣列參數可以選擇性地將另一個參數指定為數組長度參數。 當必要的陣列大小參數指定呼叫端所提供陣列中的元素數目上限時,陣列長度參數會指定被呼叫端實際填入的專案數目。
陣列長度參數是以 array 參數上的 LengthIs 屬性指定。
方法多載
在單一介面的範圍內,多個方法可能具有相同的名稱。 介面上具有相同名稱的方法必須具有唯一的簽章。 屬性和事件無法多載。
WinRT 支援參數類型的多載,但偏好在輸入參數數目上進行多載,也稱為方法的 arity。 這是為了支援動態、弱式類型語言, (例如 JavaScript) 來完成。
當介面有多個具有相同名稱和輸入參數數目的方法時,這些方法中的其中一個必須標示為預設值。 在所有具有相同名稱和輸入參數數目的多載方法中,只有標示為預設值的方法會由動態、弱式類型語言投影。 如果只有指定名稱和輸入參數數目的單一多載方法,請將它標示為預設值有效,但不需要。
為了判斷方法的 arity,陣列參數及其必要長度參數會被視為單一參數。 PassArray 和 FillArray 樣式會被視為單一輸入參數,而 ReceiveArray 樣式會被視為單一輸出參數。
當介面上的多個方法具有相同名稱時,每個碰撞方法的唯一名稱必須儲存在附加至 方法的 OverloadAttribute 中。 預設多載方法會攜帶 DefaultOverloadAttribute。
運算子多載
WinRT 不支援運算子多載。 方法不能使用特殊運算子名稱命名,例如 ECMA 335 CLI 規格、分割區 I、第 10.3 節中指定的op_Addition。
屬性
屬性是一對 get/set 方法,其名稱與類型相符,以欄位而非方法的形式出現在某些語言投影中。
屬性及其 get/set 方法必須具有公開可見度。
屬性必須有 get
方法。 屬性 getter 方法沒有參數,並傳回屬性類型的值。 只有 get
方法的屬性稱為唯讀屬性。
屬性可以選擇性地具有 set
方法。 屬性 setter 方法具有屬性類型的單一參數,並傳回 void。 具有 get
和 set
方法的屬性稱為讀取/寫入屬性。
屬性可能無法參數化。 來自參數化介面的屬性可能會使用包含型別的類型參數做為屬性類型。
事件
事件是一對具有相符名稱和委派類型的新增/移除接聽程式方法。 事件是介面在發生重要事件時通知相關物件的機制。
事件及其新增/移除接聽程式方法必須具有公開可見度。
事件 add
接聽程式方法具有事件委派類型的單一參數,並傳回Windows。Foundation.EventRegistrationToken。 事件 remove
接聽程式方法具有Windows的單一參數。Foundation.EventRegistrationToken類型,並傳回 void。
事件可能無法參數化。 來自參數化介面的事件可能會使用包含型別的類型參數做為事件委派類型。
執行階段類別
WinRT 可讓您定義類別。 類別必須實作一或多個介面。 類別無法直接 (實作類型成員,也就是說,它無法定義自己的方法、屬性或事件) 。 類別必須提供其實作之所有介面的所有成員的實作。
有數種不同的介面類別型,如下所述。
- 成員介面 (包括受保護和可覆寫的介面)
- 靜態介面
- 啟用處理站介面
- 組合處理站介面
執行時間類別無法參數化。 執行時間類別可以實作參數化介面實例 (,也就是說,參數化介面及其所有類型參數指定) 通常會接受非參數化介面。
執行時間類別必須具有公用可見度。
執行時間類別只能實作不是獨佔 (的介面,也就是不要將 exclusiveTo 屬性) 或屬於有問題的執行時間類別獨佔。 執行時間類別可能不會實作不同執行時間類別專屬的介面。 此規則有一個例外狀況,可組合類別可能會實作其衍生鏈結中標示為可覆寫之類別的專屬介面。 要遵循的可覆寫介面詳細資料。
成員介面
執行時間類別可以實作零個或多個成員介面。 成員介面可讓類別公開與 類別實例相關聯的功能。 執行時間類別會指定其實作的成員介面清單。 執行時間類別所實作成員介面清單中的專案可能會選擇性地包含版本資訊。 要遵循的執行時間類別版本設定詳細資料。
成員介面會直接在執行時間類別的實例上實作。
實作一或多個成員介面的執行時間類別必須指定其中一個成員介面做為預設介面。 實作零成員介面的執行時間類別不會指定預設介面。
靜態介面
WinRT 類別可以指定零個或多個靜態介面。 靜態介面可讓類別公開與類別本身相關聯的功能,而不是與類別的特定實例相關聯。
類別必須至少指定一個成員或靜態介面。 沒有成員且沒有靜態介面的類別無效。
靜態介面是透過與執行時間類別相關聯的 StaticAttribute 來指定。 StaticAttribute 具有靜態介面參考以及版本資訊的參考。 要遵循的執行時間類別版本設定詳細資料。
雖然靜態介面宣告為執行時間類別的一部分,但實際上不會在類別實例本身實作它們。 而是在類別的啟用處理站上實作它們。 要遵循的啟用處理站詳細資料。
啟用
執行時間類別選擇性地支援啟用—系統產生指定類別實例的能力。 類別必須實作至少一個成員介面,才能支援啟用。
WinRT 會定義三個啟用機制:直接啟用 (沒有建構函式參數) 、 (一或多個建構函式參數) ,以及組合啟用。 不可組合的類別可能支援直接和/或處理站啟用。 可撰寫類別僅支援可組合啟用。 要遵循的撰寫和可組合啟用的詳細資料。
支援直接啟用的類別會藉由在類別的啟用處理站上呼叫 IActivationFactory.ActivateInstance 方法來啟用。 這個方法不採用任何參數,並傳回新啟動的執行時間類別實例。 要遵循的啟用處理站詳細資料。
支援處理站啟用的類別會定義一或多個處理站介面,每個介面會接著定義一或多個處理站方法。 這些處理站介面會在 類別的啟用處理站上實作。
Factory 方法會採用一或多個 in
參數,而且必須傳回新啟動的執行時間類別實例。 不允許新啟動類別實例以外的其他 out
參數。 Factory 方法必須採用一或多個參數—不允許無參數處理站啟用。 直接啟用必須用於無參數啟用。
支援直接啟用或原廠啟用的類別會標示為 ActivationableAttribute。 ActivatableAttribute 具有版本資訊, (執行時間類別版本設定的詳細資料,以遵循) 以及處理站介面的選擇性參考。 類別可以標示多個 ActivationableAttributes—最多一個用於預設啟用,以及類別啟用處理站所實作的每個處理站介面。 以 ActivatableAttribute 標記的類別不一定也會以 ComposableAttribute 標示。 要遵循的撰寫詳細資料。
Composition
執行時間類別可以選擇性地支援組合,讓多個類別實例能夠合併成似乎來自外部的單一物件。 WinRT 使用組合做為執行時間類別繼承的形式。
WinRT 類別可以選擇性地撰寫單一可組合基類,進而撰寫單一可組合基類等等。類別本身不需要可組合,才能撰寫可組合的基類。 類別只能以可組合類別做為基類來撰寫。 撰寫另一個可撰寫類別不需要撰寫類別, (也就是說,它可能是階層) 的根目錄。 不允許組合 (的圓形圖表,例如 A composes B,其組成 A) 。
在執行時間,撰寫類別是 WinRT 物件的匯總,一個用於組合鏈結中的每個物件。 這些匯總物件會將識別和存留期委派給組合鏈結中原本啟動的物件, (稱為控制物件) 。 鏈結中的每個物件都會保留它所撰寫類別的非委派 IInspectable 指標,以便在撰寫的基類介面上呼叫方法,包括受保護介面上的方法。 鏈結中的每個物件都有控制類別的指標,可用來委派存留期和身分識別,以及呼叫可覆寫介面上的方法。 要遵循的受保護和可覆寫介面詳細資料。
讓我們來看看 Button 撰寫 Control的範例,該控制項接著會撰寫 UIElement。 在該範例中, Button 的實例會匯總 Control 實例,進而匯總 UIElement 實例。 這三個物件都有 Button 物件的參考,可用來控制存留期和身分識別,以及查詢可覆寫介面。 每個物件都有一個 IInspectable 指標,指向它所撰寫的物件 (Button 會保留 Control的指標; 控制項 會保留 UIElement) 的指標,以便能夠在撰寫類別上實作的介面上呼叫方法,包括受保護的介面。
除非介面在可撰寫類別中標示為可覆寫,否則類別可能不會實作它所撰寫類別上定義的任何介面,也不會實作組合鏈結中的任何類別。 要遵循的可覆寫介面詳細資料。
可撰寫類別必須以一或多個 ComposableAttributes 標記。 ComposableAttribute 具有組合處理站介面的參考,不論組合處理站介面上的 Factory 方法是否可以用於控制物件啟用,以及版本資訊。 撰寫處理站介面和版本設定的詳細資料。 類別可以使用多個 ComposableAttributes 標記,每個組合處理站介面各一個由類別的啟用處理站實作。
JavaScript 語言投影不支援類別組合。 因此,撰寫可撰寫類別和撰寫可撰寫類別的類別應該以 WebHostHiddenAttribute 標記,指出 JavaScript 不應該嘗試投影這些類型。
協力廠商只能定義撰寫其他可撰寫類別的類別。 您不可以定義自己的可組合根類別。
可組合啟用
可組合類別必須定義一或多個組合處理站介面,接著實作一或多個組合處理站方法。 組合處理站介面會在 類別的啟用處理站上實作。 要遵循的啟用處理站詳細資料。
組合處理站介面可用來建立 類別的可組合實例。 可組合處理站介面會宣告零個或多個可組合處理站方法,可用來啟用類別的實例以供組合之用。 請注意,使用零處理站方法的可組合處理站介面是合法的。 這表示類別可用於組合,但協力廠商可能不會直接撰寫類別,否則方法 (建立實例) 僅供內部使用。
可撰寫類別會宣告指定組合處理站介面上的 Factory 方法是否可用來直接啟動類別做為控制物件。 標示為公用的可組合處理站介面可用來直接啟動類別做為控制物件,以及間接啟動類別做為撰寫物件。 標示為受保護之可組合處理站介面只能用來間接啟動類別做為撰寫物件。 可撰寫類別一律可以啟動為組成物件。
組合處理站介面必須是 exclusiveto
它所實作的執行時間類別。
如同啟用處理站方法,組合處理站方法必須傳回可撰寫類別的實例。 此外,組合處理站方法有兩個額外的參數:控制 IInspectable* [in] 參數,以及非委派 IInspectable** [out] 參數。 組合處理站方法可以選擇性地具有其他 in
參數。 如果指定,則必須先在方法簽章的開頭髮生其他 in 參數,才能在先前列出的強制參數之前。 組合處理站方法可能沒有非委派IInspectable**和傳回值參數以外的任何其他 out
參數。
當可組合類別啟動 (例如,當 Button實例啟動) 時,控制項實例或UIElement會透過控制IInspectable* [in] 參數傳入控制身分識別和存留期的物件指標。 可組合處理站方法會傳回新啟動的實例作為傳回值。 此實例會將所有身分識別和存留期管理功能委派給提供的控制 IInspectable* 。 此外,可組合處理站方法會傳回非委派 IInspectable* 的指標,讓撰寫類別可用來在撰寫類別上叫用方法。
當可組合類別啟動為控制類別 (例如,上一個範例中的 Button) 時,會使用與啟用組合相同的可組合處理站方法。 直接啟用可撰寫類別時,會針對控制 *IInspectable* 參數傳遞 null。 這是可組合類別的指標,表示它正在啟動為控制類別。 當控制類別建立所撰寫類別的實例時,它會將參考傳遞至本身做為控制 IInspectable* 參數。 可組合的 Factory 方法會將控制類別實例當做傳回值傳回。 啟用控制可撰寫類別時,用戶端程式代碼會忽略非委派 IInspectable** [out] 參數。
建置在先前的Button - >Control - >UIElement範例上,按鈕類別會藉由呼叫其中一個組合處理站方法並傳遞外部參數的 Null 來啟動。 按鈕 會接著啟動 Control 實例,並將參考傳遞至本身做為外部參數。 控制項 會接著啟動 UIElement 實例,並傳遞它收到的外部參考做為外部參數。 UIElement Factory 方法會返回控制實例參數中新建立的UIElement,以及內部參數中UIElement非委派IInspectable的參考。 Control Factory 方法會傳回Button實例參數中新建立的Control,以及在內部參數中對 Control的非委派IInspectable參考。 按鈕組合處理站會傳回呼叫程式碼,在實例參數中新建立的 Button,內部參數則傳回 null。
類別有時可能會針對組合啟用,而其他時候會啟動為控制類別。 例如,如果RadioButton撰寫按鈕,則在啟動 RadioButton時,就會啟動 Button進行組合;但是當Button直接啟用時,會啟動為控制類別。 不論是哪一種情況,按鈕撰寫的Control類別都會針對組合啟用。
受保護的介面
可組合類別可以宣告要保護的零或多個成員介面。 不可組合的類別可能不會宣告要保護的成員介面。 只有撰寫可撰寫類別 (直接或間接) 之類別中的程式碼,才能查詢並使用可撰寫類別宣告為受保護的介面。 來自組合鏈結外部的程式碼可能不會查詢或使用可撰寫類別宣告為受保護的介面。
例如,如果 UIElement 宣告受保護的介面 IUIElementProtected,則只有撰寫 UIElement的類別,包括直接 (Control) 和間接 (Button) 組合,可能會查詢並使用 IUIElementProtected 介面。
可覆寫的介面
可撰寫類別可以宣告零個或多個要覆寫的成員介面。 可覆寫的介面只能查詢和使用於組合鏈結中,類似于存取先前詳述之受保護介面的規則。 不過,如果受保護的介面只能由原本宣告它的類別實作,則可覆寫介面可由撰寫實作可覆寫介面之類別的類別重新實作。
在執行時間,利用可覆寫介面的任何可撰寫類別程式碼,都必須透過用於身分識別和存留期委派的控制 IInspectable* 指標,查詢介面的 QueryInterface。 此指標會傳回組合鏈結中最早可覆寫介面的實作, (也就是最接近控制類別實例) 。 想要存取所撰寫類別的可覆寫介面的類別,可以透過可撰寫類別保留給其撰寫類別的非委派參考來執行此動作。
讓我們採用 UIElement 宣告可覆寫介面 IUIElementOverridable的範例。 在此情況下,衍生自 UIElement的類別,包括直接 (Control) 和間接 (Button) 衍生,都可以實作它。 如果 UIElement 中的程式碼需要存取 IUIElementOverridable中的功能, UIElement 會查詢控制 IInspectable ,以取得撰寫鏈結中的最早實作。 如果Control和Button都已實作IUIElementOverridable,則會在查詢控制IInspectable時傳回Button實作。 如果 Button 想要存取其撰寫類別功能,則可以使用從組合處理站方法傳回的非委派 IInspectable 來查詢該介面的基類。
啟用 Factory
執行時間類別選擇性地具有啟用處理站。 如果類別為可啟用、可組合或具有靜態介面,則執行時間類別必須具有啟用處理站。 類別的啟用處理站可以透過 RoGetActivationFactory Win32 函式從系統擷取。
Activation Factory 必須實作 IActivationFactory 介面。 不過,只有支援直接啟用的類別會實作 IActivationFactory的單一方法 ActivateInstance。 不支援直接啟用的類別必須從IActivationFactory.ActivateInstance傳回L E_NOTIMPL。
啟用處理站必須實作執行時間類別上定義的所有啟用處理站介面、組合處理站介面和靜態介面。
不保證語言投影會在處理站存留期內維護單一啟用處理站實例。 需要儲存長期資訊以進行靜態成員存取的 WinRT 類別作者,必須將它儲存在啟用處理站外的某處。
以類別為基礎的投影
雖然 WinRT 主要是介面型程式設計模型,但執行時間類別提供更符合現代化、主要、物件導向 (OO) 程式設計語言的類別型程式設計模型。 語言投影預期會將執行時間類別投影為單一實體,而不是開發人員必須個別處理的介面包。
為了達成這個以類別為基礎的模型,語言投影預期會將類別成員介面中的類型成員投影為直接類別成員。 語言投影預期會將類別靜態介面中的類型成員投影為靜態類別成員。 最後,語言投影預期會投影啟用方法, (直接啟用,以及來自處理站和可組合處理站介面的介面,) 為類別建構函式。
為了協助進行這個類別型投影,執行時間類別的中繼資料會指定其實作之每個介面之所有方法、屬性和事件的類別成員。 每個類別成員都會明確系結回原先定義的介面成員。 這可讓語言投影將類別公開為單一實體,並代表開發人員處理所有介面查詢和參考計數。
根據預設,每個實作的介面成員都會投影為類別成員。 不過,由於執行時間類別可以實作一段時間的多個獨立介面和版本, (版本設定詳細資料要遵循) ,因此單一執行時間類別所實作之不同介面上定義的成員可能會發生名稱衝突。
發生衝突時,不可能使用預設類別成員投影。 如果在不同版本中新增的介面之間發生衝突,則會將來自最早版本的碰撞成員投影為類別成員。 在相同版本中新增的介面間發生衝突時,不會將任何衝突成員投影為類別成員。 請注意,只要所有版本都是不同 arity ,就允許具有碰撞名稱的方法,如 方法多載中所述。
未投影為類別成員的介面成員必須提供給開發人員使用。 一般而言,這是由轉型或動態查閱運算子完成,可讓開發人員指定想要叫用的特定介面和方法。
為了解決方法名稱衝突,執行時間類別可能會指定其實作之成員和靜態介面上方法的替代名稱。 此替代名稱是由語言投影用來提供與類別實例衝突方法名稱的去除混淆存取。 雖然執行時間類別可能會提供替代的方法名稱,但方法簽章、參數,以及附加至方法或其屬性的任何屬性,仍然必須完全符合原始介面定義。
由於直接啟用、處理站方法和組合處理站方法會投影為類別建構函式,因此它們全都會投影在執行時間類別上,就像它們具有相同的名稱一樣。 所有處理站介面上的所有方法都必須有唯一的簽章、應該優先使用 以 arity為基礎的多載,而非以類型為基礎的多載,而且必須使用 DefaultOverloadAttribute 來厘清相同 arity 的處理站方法。
類別版本控制
執行時間類別可加加版本設定。 給定執行時間類別的後續版本可能會指定所有類型的其他介面,並進一步詳述以下個別介面類別型的詳細資料。 類別所指定的既有介面永遠不會移除或變更,而不會中斷回溯相容性。
成員介面版本控制
執行時間類別上的成員介面可加加版本設定。 給定執行時間類別的後續版本可能會實作額外的成員介面,即使類別先前從未實作成員介面也一樣。 給定可組合執行時間類別的後續版本可能會實作額外的受保護和可覆寫介面。
執行時間類別所實作的介面會選擇性地攜帶 VersionAttribute,以區別何時將特定介面新增至執行時間類別類型。 沒有 VersionAttribute 的介面實作值會被視為具有與封入執行時間類別類型相同的版本值。
靜態介面版本控制
執行時間類別上的靜態介面可加總版本設定。 給定執行時間類別的後續版本可能會實作額外的靜態介面,即使類別先前從未實作靜態介面也一樣。
StaticAttribute 包含版本號碼的UInt32參數,該參數會定義新增該啟用支援的Windows版本。
啟用版本控制
執行時間類別的啟用支援可加總版本設定。 給定執行時間類別的後續版本可能會實作額外的啟用機制,即使類別從未實作啟用機制也一樣。 請注意,可組合類別無法啟用,因此可能不會新增啟用支援。
請注意,支援直接啟用的類別只能新增處理站啟用介面。 先前僅支援處理站啟用的類別可能會新增直接啟用支援,以及新的處理站啟用介面。
ActivatableAttribute 包含版本號碼的 UInt32 參數。 ActivationableAttribute 的版本號碼會定義新增該啟用支援的Windows版本。
組合版本控制
執行時間類別的組合支援可加法設定版本。 給定可組合執行時間類別的後續版本可能會實作其他組合機制,前提是類別在建立時定義為可組合。 可撰寫的類別可能不會新增啟用支援。
ComposableAttribute 包含版本號碼的 UInt32 參數。 ComposableAttribute 的版本號碼會定義新增該組合支援的Windows版本。
自訂屬性
WinRT 支援自訂中繼資料屬性的定義。 WinRT 類型系統中的所有建構都可以包含自訂中繼資料屬性。 這包括所有具名類型 (列舉、結構、委派、介面、類別等) ,以及類型建構中包含的個別專案 (,例如方法、參數等) 。
自訂屬性的名稱就像其他 WinRT 類型一樣。 不過,它們無法啟動。 它們只是資料建構。
自訂屬性會定義位置參數或具名欄位的資料架構。 自訂屬性不能同時使用位置參數和具名欄位,它必須選擇其中一個或另一個。 自訂屬性的參數和欄位的類型僅限於 WinRT 基本類型、列舉和其他 WinRT 類型的參考。 不允許其他參數或欄位類型。
使用位置參數的自訂屬性必須定義一或多個有效的位置參數集合。 每個集合都必須指定零個或多個位置參數。 自訂屬性的實例必須指定單一位置參數集,以及所選集合中每個位置參數的資料。
使用具名欄位的自訂屬性會指定具有名稱和類型的零欄位。 自訂屬性的實例必須為其想要指定的欄位指定名稱/值組。 實例可以指定所有、部分或無名稱/值組的值。
屬性沒有位置參數或具名欄位都有效。
自訂屬性必須具有公開可見度。
屬性可以指定可透過 AttributeUsageAttribute 與其相關聯的 WinRT 類型建構類型。
協力廠商無法定義自訂屬性。 僅支援系統定義的自訂屬性。