Microsoft インターフェイス定義言語 3.0 の概要
Microsoft Interface Definition Language (MIDL) 3.0 は、インターフェイス定義言語 (IDL) ファイル (.idl
ファイル) 内で Windows ランタイム型を定義するための簡略化された最新の構文です。 この新しい構文は、C、C++、C#、Java の経験を持つすべてのユーザーにとってなじみのあるものになります。 MIDL 3.0 は、C++/WinRT ランタイム クラス
MIDL 3.0 の外観を次に示します。この例では、使用する可能性のあるほとんどの言語構文要素を示します。
// Photo.idl
namespace PhotoEditor
{
delegate void RecognitionHandler(Boolean arg); // delegate type, for an event.
runtimeclass Photo : Windows.UI.Xaml.Data.INotifyPropertyChanged // interface.
{
Photo(); // constructors.
Photo(Windows.Storage.StorageFile imageFile);
String ImageName{ get; }; // read-only property.
Single SepiaIntensity; // read-write property.
Windows.Foundation.IAsyncAction StartRecognitionAsync(); // (asynchronous) method.
event RecognitionHandler ImageRecognized; // event.
}
}
MIDL 3.0 の構文は、 型を定義 midl.exe
バージョン 8.01.0622 以降、/winrt
スイッチで使用) が必要です。
手記
Windows ランタイム統合リファレンス (
MIDL 1.0、2.0、3.0
インターフェイス定義言語 (IDL) は、分散コンピューティング環境/リモート プロシージャ コール (DCE/RPC) システムから始まりました。 元の MIDL 1.0 は、COM インターフェイスとコクラスを定義するための拡張機能を備えた DCE/RPC IDL です。
更新された MIDL 2.0 構文 (MIDLRT とも呼ばれます) は、Windows プラットフォーム用の Windows ランタイム API を宣言するために Microsoft 内で開発されました。
%WindowsSdkDir%Include<WindowsTargetPlatformVersion>\winrt
Windows SDK フォルダーを見ると、MIDL 2.0 構文で記述された .idl
ファイルの例が表示されます。 これらは組み込みの Windows ランタイム API であり、アプリケーション バイナリ インターフェイス (ABI) 形式で宣言されています。 これらのファイルは主にツールで使用するために存在します。この形式でこれらの API を作成したり使用したりすることはありません (非常に低レベルのコードを記述している場合を除きます)。
また、従来の MIDLRTから MIDL 3.0 への移行を参照してください。
MIDL 3.0 は、Windows ランタイム API を宣言することを目的とする、はるかにシンプルでモダンな構文です。 また、特に C++/WinRT ランタイム クラス %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt
フォルダー内の SDK の一部です。
MIDL 3.0 のユース ケース
一般に、すべての Windows ランタイム API は、すべての Windows ランタイム言語プロジェクションで使用できるように設計されています。 これは部分的に、Windows ランタイム API との間で Windows ランタイム型を排他的に渡すように選択することで行われます。 Windows ランタイム API との間で生の COM インターフェイスを渡すことが有効な設計上の決定ですが、これを行うと、その特定の Windows ランタイム API のコンシューマーが C++ アプリケーションに制限されます。 この手法は、相互運用シナリオ (Direct3D と XAML の間で相互運用する場合など) で確認できます。 Direct3D は図に含まれているので、シナリオは必ずしも C++ アプリケーションに絞り込まれます。 そのため、COM インターフェイスを必要とする API では、固有の制限以上の制限は課されません。 たとえば、C++ アプリケーションでは、IDXGISwapChain インターフェイス ポインターを取得し、それを ISwapChainPanelNative::SetSwapChain メソッドに渡すことができます。 たとえば、C# アプリケーションでは、最初に IDXGISwapChain windows.ui.xaml.media.dxinterop.h
などの相互運用ヘッダーで実行されます。
C++ 以外の Windows ランタイム言語プロジェクションに公開する COM コンポーネントの機能
定義構造とコマンド ラインからの midl.exe の呼び出し
MIDL 3.0 定義の主要な組織の概念は、名前空間、型、およびメンバーです。 MIDL 3.0 ソース ファイル (.idl
ファイル) には少なくとも 1 つの名前空間が含まれており、その中には型や下位の名前空間があります。 各型には、0 個以上のメンバーが含まれています。
- クラス、インターフェイス、構造体、および列挙型は型です。
- メソッド、プロパティ、イベント、およびフィールドは、メンバーの例です。
MIDL 3.0 ソース ファイルをコンパイルすると、コンパイラ (midl.exe
) によって Windows ランタイム メタデータ ファイル (通常は .winmd
ファイル) が出力されます。
// Bookstore.idl
namespace Bookstore
{
runtimeclass BookSku : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
BookSku();
BookSku(Single price, String authorName, String coverImagePath, String title);
Single Price;
String AuthorName{ get; };
Windows.UI.Xaml.Media.ImageSource CoverImage{ get; };
String CoverImagePath{ get; };
String Title{ get; };
Boolean Equals(BookSku other);
void ApplyDiscount(Single percentOff);
}
}
Windows ランタイム型の名前空間は型名の一部になるため、上の例では Bookstore.BookSkuという名前
このクラスは、Windows.UI.Xaml.Data.INotifyPropertyChanged インターフェイス
先端
Visual Studio は、C++/WinRT Visual Studio Extension (VSIX) を使用して MIDL 3.0 をコンパイルするための最適なエクスペリエンスを提供します。 C++/WinRT Visual Studio のサポートと VSIXに関するページを参照してください。
ただし、コマンド ラインから MIDL 3.0 をコンパイルすることもできます。 この例のソース コードが Bookstore.idl
という名前のファイルに格納されている場合は、次のコマンドを発行できます。 ケースに必要な場合は、コマンドで使用されている SDK バージョン番号 (10.0.17134.0) を更新できます。
midl /winrt /metadata_dir "%WindowsSdkDir%References\10.0.17134.0\windows.foundation.foundationcontract\3.0.0.0" /h "nul" /nomidl /reference "%WindowsSdkDir%References\10.0.17134.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd" /reference "%WindowsSdkDir%References\10.0.17134.0\Windows.Foundation.UniversalApiContract\6.0.0.0\Windows.Foundation.UniversalApiContract.winmd" /reference "%WindowsSdkDir%\References\10.0.17134.0\Windows.Networking.Connectivity.WwanContract\2.0.0.0\Windows.Networking.Connectivity.WwanContract.winmd" Bookstore.idl
midl.exe
ツールは、例をコンパイルし、Bookstore.winmd
という名前のメタデータ ファイルを生成します (既定では、.idl
ファイルの名前が使用されます)。
先端
複数の IDL ファイルを使用する場合 (詳細については、「ランタイム クラスを Midl ファイル (.idl)にファクターする」を参照してください)、結果として得られる .winmd
ファイルをすべて、ルート名前空間と同じ名前の 1 つのファイルにマージします。 最終的な .winmd
ファイルは、API のコンシューマーが参照するファイルになります。
この場合、bookSku
なお、where
コマンドを使用して、midl.exe
がインストールされている場所を確認できます。
where midl
別の .idl
ファイルの 1 つの .idl
ファイルで定義されている型を使用する場合は、import
ディレクティブを使用します。 詳細とコード例については、XAML コントロール 参照してください。C++/WinRT プロパティにバインドします。 もちろん、組み込みコンポーネントまたはサード パーティ製コンポーネントを使用している場合は、.idl
ファイルにアクセスできません。 たとえば、Win2D Windows ランタイム API を使用して、イミディエイト モードの 2D グラフィックス レンダリングを行うことができます。 上記のコマンドでは、/reference
スイッチを使用して Windows ランタイム メタデータ (.winmd
) ファイルを参照しました。 この次の例では、このスイッチをもう一度使用し、Bookstore.winmd
があるが、Bookstore.idl
していないシナリオを想像します。
// MVVMApp.idl
namespace MVVMApp
{
runtimeclass ViewModel
{
ViewModel();
Bookstore.BookSku BookSku{ get; };
}
}
上記の例のソース コードが MVVMApp.idl
という名前のファイルに格納されている場合は、次のコマンドを発行して Bookstore.winmd
を参照できます。
midl /winrt /metadata_dir "%WindowsSdkDir%References\10.0.17134.0\windows.foundation.foundationcontract\3.0.0.0" /h "nul" /nomidl /reference "%WindowsSdkDir%References\10.0.17134.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd" /reference "%WindowsSdkDir%References\10.0.17134.0\Windows.Foundation.UniversalApiContract\6.0.0.0\Windows.Foundation.UniversalApiContract.winmd" /reference "%WindowsSdkDir%\References\10.0.17134.0\Windows.Networking.Connectivity.WwanContract\2.0.0.0\Windows.Networking.Connectivity.WwanContract.winmd" /reference Bookstore.winmd MVVMApp.idl
名前空間
名前空間が必要です。 名前空間ブロックのスコープで定義されているすべての型の名前の前に、名前空間名を付けます。 名前空間には、下位の名前空間宣言を含めることもできます。 下位の名前空間スコープで定義されている型の名前には、含まれるすべての名前空間名のプレフィックスがあります。
次の例は、同じ Windows.Foundation.Uri クラスを宣言する 2 つの方法です (ご覧のとおり、ピリオドは入れ子になった名前空間のレベルを区切ります)。
namespace Windows.Foundation
{
runtimeclass Uri : IStringable
{
...
}
}
namespace Windows
{
namespace Foundation
{
runtimeclass Uri : IStringable
{
...
}
}
}
名前空間とその型を入れ子にして宣言することが有効であることを示す別の例を次に示します。
namespace RootNs.SubNs1
{
runtimeclass MySubNs1Class
{
void DoWork();
}
namespace SubNs2
{
runtimeclass MySubNs2Class
{
void DoWork();
}
}
}
ただし、以前の名前空間を閉じて、次のように新しい名前空間を開く方が一般的です。
namespace RootNs.SubNs1
{
runtimeclass MySubNs1Class
{
void DoWork();
}
}
namespace RootNs.SubNs1.SubNs2
{
runtimeclass MySubNs2Class
{
void DoWork();
}
}
種類
MIDL 3.0 には、値型と参照型の 2 種類のデータ型があります。 値型の変数には、そのデータが直接含まれています。 参照型の変数は、そのデータへの参照を格納します (このような変数は、オブジェクトとも呼ばれます)。
2 つの参照型変数で同じオブジェクトを参照できます。 したがって、1 つの変数に対する操作は、もう一方の変数によって参照されるオブジェクトに影響します。 値型では、変数にはそれぞれデータのコピーがあり、一方の操作がもう一方に影響を与えることはできません。
MIDL 3.0 の値型は、さらに単純型、列挙型、構造体型、および null 許容型に分割されます。
MIDL 3.0 の参照型は、さらにクラス型、インターフェイス型、デリゲート型に分割されます。
MIDL 3.0 の型システムの概要を次に示します。 以前のバージョンの MIDL とは異なり、これらの型にはエイリアスを使用できません。
カテゴリ | 形容 | |
---|---|---|
値型 | 単純型 | 符号付き整数: Int16, Int32, Int64 |
符号なし整数: UInt8 |
||
Unicode 文字: Char (UTF-16LE、16 ビット Unicode コード単位を表します) | ||
Unicode 文字列: 文字列 | ||
IEEE 浮動小数点: Single、 Double | ||
Boolean: Boolean | ||
128 ビット UUID: Guid | ||
列挙型 | フォームのユーザー定義型 列挙型 E {...} | |
構造体の型 | 構造体 S {...} |
|
Null 許容型 | null 値を持つ他のすべての値型の拡張 | |
参照型 | クラス型 | 他のすべての型の Ultimate 基底クラス: Object |
ランタイム クラス C {...} |
||
インターフェイスの種類 | フォームのユーザー定義型 インターフェイス I {...} | |
デリゲート型 | フォームのユーザー定義型 デリゲート <returnType> D(...) |
7 つの整数型は、8 ビット符号なしデータをサポートします。符号付きまたは符号なし形式の 16 ビット、32 ビット、64 ビットの値。
2 つの浮動小数点型 単精度 と 倍精度は、それぞれ 32 ビットの単精度と 64 ビットの倍精度 IEEE 754 形式を使用してデータを表します。
MIDL 3.0 の ブール 型はブール値を表します。true
または false
。
MIDL 3.0 の文字と文字列には Unicode 文字が含まれています。 Char 型は UTF-16LE コード単位を表します。文字列 型は、UTF-16LE コード単位のシーケンスを表します。
次の表は、MIDL 3.0 の数値型をまとめたものです。
カテゴリ | ビット | 種類 | 範囲/有効桁数 |
---|---|---|---|
符号付き整数 | 16 | Int16 | –32,768...32,767 |
32 | Int32 | –2,147,483,648...2,147,483,647 | |
64 | Int64 | –9,223,372,036,854,775,808...9,223,372,036,854,775,807 | |
符号なし整数 | 8 | UInt8 を |
0...255 |
16 | UInt16 を |
0...65,535 | |
32 | UInt32 を |
0...4,294,967,295 | |
64 | UInt64 を |
0...18,446,744,073,709,551,615 | |
浮動小数点 | 32 | Single | 1.5 × 10-45 ~ 3.4 × 1038、7 桁の精度 |
64 | ダブル | 5.0 × 10-324 から 1.7 × 10308、15 桁の精度 |
MIDL 3.0 ソース ファイルでは、型定義を使用して新しい型を作成します。 型定義では、新しい型の名前とメンバーを指定します。 これらの MIDL 3.0 型のカテゴリは、ユーザー定義可能です。
- 属性の型、
- 構造体の型
- インターフェイスの種類、
- runtimeclass 型、
- デリゲート型、および
- 列挙型。
属性 型は、他の型定義に適用できる Windows ランタイム属性を定義します。 属性は、属性が適用される型に関するメタデータを提供します。
構造体 型は、データ メンバー (フィールド) を含む Windows ランタイム構造体を定義します。 構造体は値型であり、ヒープ割り当てを必要としません。 構造体型のデータ メンバーは、値型または null 許容型である必要があります。 構造体型は継承をサポートしていません。
インターフェイス 型は、関数メンバーの名前付きセットである Windows ランタイム インターフェイスを定義します。 インターフェイスは、インターフェイスの実装で、指定された 1 つ以上の追加 (必須) インターフェイスも実装する必要があることを指定できます。 すべてのインターフェイスの種類は、Windows ランタイム IInspectable インターフェイスから直接派生します。
ランタイムクラス 型は、Windows ランタイム クラス (ランタイム クラス) を定義します。 ランタイム クラスには、プロパティ、メソッド、およびイベントを指定できるメンバーが含まれています。
デリゲート 型は、特定のパラメーター リストと戻り値の型を持つメソッドへの参照を表す Windows ランタイム デリゲートを定義します。 デリゲートを使用すると、メソッドをパラメーターとして渡すことができるエンティティとして扱うことができます。 デリゲートは、他の言語で見つかる関数ポインターの概念に似ています。 関数ポインターとは異なり、デリゲートはオブジェクト指向であり、型セーフです。
列挙型 型は、名前付き定数を持つ個別の型です。 すべての列挙型には暗黙的な基になる型があります。Int32
MIDL 3.0 では、追加の 3 種類のカテゴリがサポートされています。
- 1 次元配列型、
- null 許容値型、および
- オブジェクト 型。
使用する前に、1 次元配列を宣言する必要はありません。 代わりに、配列型は、角かっこで囲まれた型名に従って構築されます。 たとえば、Int32[] は、Int32の 1 次元配列です。
同様に、null 許容 値型も、使用する前に定義する必要はありません。 (文字列を除 null
を保持できる型です。 IReference
最後に、MIDL 3.0 では、Windows ランタイム IInspectable インターフェイスにマップされる Object 型がサポートされています。
列挙値の式
MIDL 3.0 では、列挙型の名前付き定数の値の定義に
式は、オペランド および 演算子から構築されます。 式の演算子は、オペランドに適用する演算を示します。 演算子の例としては、+、-、*、/、および new
があります。 オペランドの例としては、リテラル、フィールド、ローカル変数、および式があります。
式に複数の演算子が含まれている場合、演算子の 優先順位 によって、個々の演算子の評価順序が制御されます。 たとえば、式 x + y * z は x + (y * z) として評価されます。これは、* 演算子が + 演算子よりも優先順位が高いためです。 論理演算は、ビットごとの演算よりも優先順位が低くなります。
次の表は、MIDL 3.0 の演算子をまとめたものです。演算子のカテゴリは、優先順位の高い順に一覧表示されます。 同じカテゴリの演算子の優先順位は同じです。
カテゴリ | 表現 | 形容 |
---|---|---|
原発 | x++ | インクリメント後 |
x-- | デクリメント後 | |
単項 | +x | 同一性 |
-x | 否定 | |
!x | 論理否定 | |
~x | ビットごとの否定 | |
++x | 事前インクリメント | |
--x | 事前デクリメント | |
乗算 | x * y | 掛け算 |
x / y | 除法 | |
x % y | 剰余 | |
添加物 | x + y | 加算、文字列連結、デリゲートの組み合わせ |
x – y | 減算、デリゲートの削除 | |
動く | x << y | 左にシフト |
x >> y | 右にシフト | |
ビットごとの AND | x & y | 整数ビットごとの AND |
ビットごとの XOR | x ^ y | 整数ビットごとの XOR |
ビットごとの OR | x |y | 整数ビットごとの OR |
論理 AND | x && y | ブール論理 AND |
論理 OR | x ||y | ブール論理 OR |
クラス
クラス (またはランタイム クラス) は、MIDL 3.0 の型の最も基本的なものです。 クラスは、メソッド、プロパティ、およびイベントを 1 つの単位で集計する定義です。 クラスは
クラス定義を使用して、新しいクラス型を定義します。 クラス定義は、runtimeclass
キーワード、クラスの名前、基底クラス (指定されている場合)、およびクラスによって実装されるインターフェイスを指定するヘッダーで始まります。 ヘッダーの後に、区切り記号 { と }の間に書き込まれたメンバー宣言のリストで構成されるクラス本体が続きます。
Areaという名前の単純なクラス
runtimeclass Area
{
Area(Int32 width, Int32 height);
Int32 Height;
Int32 Width;
static Int32 NumberOfAreas { get; };
}
これにより、
既定では、ランタイム クラスはシールされ、そこからの派生は許可されません。 基底クラス を参照してください。
XAML をビュー モデルにバインドするには、ビュー モデル ランタイム クラスを MIDL で定義する必要があります。 XAML コントロール 参照してください。詳細については、 C++/WinRT プロパティにバインドします。
ランタイム クラス定義の前に static
キーワードを付けることで、クラスでインスタンスがサポートされていないことを宣言できます (したがって、静的メンバーのみを含める必要があります)。 クラスに非静的メンバーを追加すると、コンパイル エラーが発生します。
static runtimeclass Area
{
static Int32 NumberOfAreas { get; };
}
静的クラスは空のクラスとは異なります。 空のクラス も参照してください。
ランタイム クラス定義の前に partial
キーワードを付けることで、クラス定義が不完全であることを示すことができます。 コンパイラによって検出されるすべての部分クラス定義は、1 つのランタイム クラスに結合されます。 この機能は主に、部分的なクラスの一部がマシンで生成される XAML 作成シナリオ用です。
修飾子 | 意味 |
---|---|
静的 | クラスにはインスタンスがありません。 その結果、静的メンバーのみが許可されます。 |
パーシャル | クラス定義が不完全です。 |
高度な修飾子については、「コンポジションとアクティブ化の」を参照してください。
メンバー アクセス修飾子
MIDL 3.0 は Windows ランタイム型のパブリック サーフェスを記述するための定義言語であるため、メンバーのパブリック アクセシビリティを宣言するための明示的な構文は必要ありません。 すべてのメンバーは暗黙的にパブリックです。 そのため、MIDL 3.0 では 、(実質的に冗長な) public
キーワードは必要ありません。
基底クラス
クラス定義では、クラス名と型パラメーターにコロンと基底クラスの名前を付けて、基底クラスを指定できます。 基底クラスの指定を省略することは、オブジェクト
手記
ビュー モデル クラス (実際には、アプリケーションで定義するランタイム クラス) は、基底クラスから派生する必要はありません。
基底クラスから派生
XAML コントロール 参照してください。詳細については、 C++/WinRT プロパティにバインドします。
次の例では、
unsealed runtimeclass Area : Windows.UI.Xaml.DependencyObject
{
Area(Int32 width, Int32 height);
Int32 Height;
Int32 Width;
}
runtimeclass Volume : Area
{
Volume(Int32 width, Int32 height, Int32 depth);
Int32 Depth;
}
手記
ここで、領域 と
クラスは、その基底クラスのメンバーを継承します。 継承とは、基底クラスのコンストラクターを除き、基底クラスのすべてのメンバーがクラスに暗黙的に含まれていることを意味します。 派生クラスは、継承するメンバーに新しいメンバーを追加できますが、継承されたメンバーの定義を削除することはできません。
前の例では、
一般に、型解決規則では、参照時に型名を完全修飾する必要があります。 例外は、型が現在の型と同じ名前空間で定義されている場合です。 上の例は、Area と Volume の両方が同じ名前空間にある場合に記述されているように動作します。
実装されたインターフェイス
クラス定義では、クラスが実装するインターフェイスの一覧を指定することもできます。 (省略可能) 基底クラスに続くインターフェイスのコンマ区切りリストとしてインターフェイスを指定します。
次の例では、
unsealed runtimeclass Area : Windows.Foundation.IStringable
{
Area(Int32 width, Int32 height);
Int32 Height;
Int32 Width;
}
runtimeclass Volume : Area, Windows.Foundation.IStringable, IEquatable
{
Volume(Int32 width, Int32 height, Int32 depth);
Int32 Depth;
}
MIDL では、クラスでインターフェイスのメンバーを宣言しません。 もちろん、実際の実装で宣言して定義する必要があります。
メンバーズ
クラスのメンバーは、静的メンバー またはインスタンス メンバー 。 静的メンバーはクラスに属します。 インスタンス メンバーは、オブジェクト (つまり、クラスのインスタンス) に属します。
次の表は、クラスに含めることができるメンバーの種類を示しています。
メンバーの種類 | 形容 |
---|---|
コンス トラクター | クラスのインスタンスを初期化したり、クラス自体を初期化したりするために必要なアクション |
プロパティ | クラスのインスタンスまたはクラス自体の名前付きプロパティの読み取りと書き込みに関連付けられているアクション |
メソッド | クラスのインスタンスまたはクラス自体によって実行できる計算とアクション |
イベント | クラスのインスタンスによって発生できる通知 |
コンス トラクター
MIDL 3.0 では、インスタンス コンストラクターの宣言がサポートされています。 インスタンス コンストラクター は、クラスのインスタンスを初期化するために必要なアクションを実装するメソッドです。 コンストラクターは静的でない場合があります。
コンストラクターは、インスタンス メソッドのように (ただし、戻り値の型を持たない) 、および包含クラスと同じ名前で宣言されます。
インスタンス コンストラクターはオーバーロードできます。 たとえば、以下の
runtimeclass Test
{
Test();
Test(Int32 x);
Test(Double x, Double y);
}
パラメーター リストの構文の詳細については、以下の
インスタンスのプロパティ、メソッド、およびイベントは継承されます。 インスタンス コンストラクターは継承されず (1 つの例外を除く)、クラスには、クラスで実際に宣言されているもの以外のインスタンス コンストラクターはありません。 クラスにインスタンス コンストラクターが指定されていない場合、クラスを直接インスタンス化することはできません。 このようなクラスの場合、通常はクラスのインスタンスを返すファクトリ メソッドが他の場所にあります。
例外は封印されていないクラスです。 封印されていないクラスには、1 つ以上の保護されたコンストラクターを含めることができます。
プロパティ
プロパティ は、概念的にはフィールド (C# フィールドや MIDL 3.0 構造体のフィールドなど) に似ています。 プロパティとフィールドはどちらも、名前と関連付けられた型を持つメンバーです。 ただし、フィールドとは異なり、プロパティはストレージの場所を示していません。 代わりに、プロパティには、プロパティの読み取りまたは書き込み時に実行する関数を指定する
プロパティは構造体のフィールドと同様に宣言されます。ただし、宣言は、区切り記号 { と }の間に書き込まれた get
キーワードや set
キーワードで終わり、セミコロンで終わる点を除きます。
get
キーワードと set
キーワードの両方を持つプロパティは、読み取り/書き込みプロパティです。
get
キーワードのみを持つプロパティは、読み取り専用プロパティです。 Windows ランタイムでは、書き込み専用プロパティはサポートされていません。
たとえば、前に示した Area
unsealed runtimeclass Area
{
Int32 Height { get; set; };
Int32 Width; // get and set are implied if both are omitted.
}
Width の宣言では、中かっこ、get
、および set
キーワードは省略されます。 省略は、プロパティが読み取り/書き込みであり、その順序で get
キーワードと set
キーワードを指定するのと意味的に同じであることを意味します(get
、その後に set
。
さらに、プロパティが読み取り専用であることを示す get
キーワードのみを指定できます。
// Read-only instance property returning mutable collection.
Windows.Foundation.Collections.IVector<Windows.UI.Color> Colors { get; };
Windows ランタイムでは、書き込み専用プロパティはサポートされていません。 ただし、既存の読み取り専用プロパティを読み取り/書き込みプロパティに変更するには、set
キーワードのみを指定できます。 このバージョンの Area を例として取ります。
unsealed runtimeclass Area
{
...
Color SurfaceColor { get; };
}
その後、SurfaceColor プロパティを読み取り/書き込み可能にする必要があり、Area の以前の定義 (たとえば、Area クラスは、毎回再コンパイルするアプリケーションの型) とのバイナリ互換性を維持する必要がない場合は、次のように既存の SurfaceColor 宣言に set
キーワードを追加するだけです。
unsealed runtimeclass Area
{
...
Color SurfaceColor { get; set; };
}
一方、バイナリの安定性 必要
その場合は、次のように、プロパティ set
キーワードをクラスの末尾にあるプロパティの追加定義に追加します。
unsealed runtimeclass Area
{
...
Color SurfaceColor { get; };
...
Color SurfaceColor { set; };
}
コンパイラは、書き込み専用プロパティのエラーを生成します。 しかし、それはここで行われているものではありません。 前述のプロパティの宣言が読み取り専用であるため、set キーワードを追加しても、書き込み専用プロパティは宣言されませんが、代わりに読み取り/書き込みプロパティが宣言されます。
プロパティの Windows ランタイムの実装は、インターフェイス上の 1 つまたは 2 つのアクセサー メソッドです。 プロパティ宣言の get キーワードと set キーワードの順序によって、バッキング インターフェイスの get アクセサー メソッドと set アクセサー メソッドの順序が決まります。
get
アクセサーは、プロパティ型 (プロパティ ゲッター) の戻り値を持つパラメーターなしのメソッドに対応します。
set
アクセサーは、値という名前の 1 つのパラメーターを持つメソッドに対応し、戻り値の型 (プロパティ セッター) はありません。
したがって、これら 2 つの宣言では、異なるバイナリ インターフェイスが生成されます。
Color SurfaceColor { get; set; };
Color SurfaceColor { set; get; };
静的プロパティとインスタンス プロパティ
メソッドと同様に、MIDL 3.0 ではインスタンス プロパティと静的プロパティの両方がサポートされています。 静的プロパティは、プレフィックスが付いた static
修飾子で宣言され、インスタンス プロパティはそれなしで宣言されます。
メソッド
メソッド は、クラスのインスタンスまたはクラス自体によって実行できる計算またはアクションを実装するメンバーです。
静的メソッド は、クラスを介してアクセスされます。
メソッドには、void
されます。
// Instance method with no return value.
void AddData(String data);
// Instance method *with* a return value.
Int32 GetDataSize();
// Instance method accepting/returning a runtime class.
// Notice that you don't say "&" nor "*" for reference types.
BasicClass MergeWith(BasicClass other);
// Asynchronous instance methods.
Windows.Foundation.IAsyncAction UpdateAsync();
Windows.Foundation.IAsyncOperation<Boolean> TrySaveAsync();
// Instance method that returns a value through a parameter.
Boolean TryParseInt16(String input, out Int16 value);
// Instance method that receives a reference to a value type.
Double CalculateArea(ref const Windows.Foundation.Rect value);
// Instance method accepting or returning a conformant array.
void SetBytes(UInt8[] bytes);
UInt8[] GetBytes();
// instance method that writes to a caller-provided conformant array
void ReadBytes(ref UInt8[] bytes);
メソッドの シグネチャ は、メソッドが宣言されているクラスで一意である必要があります。 メソッドのシグネチャは、メソッドの名前、そのパラメーターの型、およびそのパラメーターの数で構成されます。 メソッドのシグネチャには、戻り値の型は含まれません。
メソッドの可視性修飾子
メソッド メソッドが派生クラスに存在する場合、オプションの可視性修飾子が 2 つのいずれかである場合があります。
オーバーライド可能な 修飾子は、サブクラスに属するメソッド (同じ名前とシグネチャを持つ) によってこのメソッドがオーバーライドされる可能性があることを示しています。
保護された 修飾子は、このメソッドは、後続の派生クラスのメンバーのみがアクセス可能であることを示します。
メソッドのオーバーロード
メソッド オーバーロード では、パラメーターの数が異なる限り、同じクラス内の複数のメソッドが同じ名前を持つことができます (つまり、メソッドの アリティが異なります)。
runtimeclass Test
{
static void F();
static void F(Double x);
static void F(Double x, Double y);
}
手記
同じ名前のすべてのメソッドは、アリティ
パラメーター
パラメーター は、値または変数参照をメソッドに渡すために使用されます。 パラメーター は、型と名前を持つスロットと、必要に応じて修飾子キーワードを記述します。 引数 は、メソッドの呼び出し元から呼び出し先にスロットに渡される実際の値です。
メソッドのパラメーターは、メソッドの呼び出し時に指定された特定の 引数 から値を取得します。 呼び出し元と呼び出し先の間で引数を渡す方法は、パラメーターの型によって異なります。 既定では、すべてのパラメーターは入力パラメーター されます。つまり、呼び出し元から呼び出し先にのみマーシャリングされます。 修飾子キーワード
大事な
共通言語ランタイム (CLR) には、このセクションで説明されているものと似ているように見える概念と修飾子キーワードがあります。 ただし、実際にはこれらは関係なく、これらの修飾子の効果は Windows ランタイムの設計と機能に固有です。
値型は暗黙的に入力パラメーター
runtimeclass Test
{
static void Divide(Int32 x, Int32 y, out Int32 result, out Int32 remainder);
}
特別なパフォーマンス最適化として、通常は値によって完全コピーとして渡される構造体型 (および他の型なし) は、変更できない構造体へのポインターによって渡されるようにすることができます。 これは、構造体パラメーターを入力パラメーターとしてマークする ref const
(const ref
ではない) キーワードを使用して実現されますが、構造体の完全なコピーを渡す代わりに、構造体のストレージへのポインターを渡すようにマーシャラーに指示します。 ただし、構造体は不変であることに注意してください。ポインターは概念的には const ポインターです。 ボクシングは関係ありません。 これは、たとえば、Matrix4x4と同じ大きさの値を受け入れる場合に実用的な選択肢です。
runtimeclass Test
{
static Boolean IsIdentity(ref const Windows.Foundation.Numerics.Matrix4x4 m);
}
参照型は暗黙的に入力パラメーターでもあります。つまり、呼び出し元はオブジェクトを割り当て、そのオブジェクトへの参照を引数として渡します。ただし、引数はオブジェクトへの参照であるため、呼び出し先によるそのオブジェクトへの変更は、呼び出し後に呼び出し元によって観察されます。 または、out
キーワードを使用して、参照型を出力パラメーターにすることもできます。 その場合、ロールは元に戻されます。呼び出し先は、オブジェクトを割り当てて呼び出し元に返す呼び出し先です。 ここでも、ref
キーワードは参照型と共に一般的には使用できません (以下の例外を参照)。
runtimeclass Test
{
static void CreateObjectWithConfig(Config config, out MyClass newObject);
}
次の表は、値パラメーターと参照パラメーターのマーシャリング キーワードの動作をまとめたものです。
振舞い | 割り当て者 | キーワード | 種類 | 備考 |
---|---|---|---|---|
入力パラメーター | 来客 | (なし) | すべての型 | 既定の動作 |
ref const |
構造体のみ | パフォーマンスの最適化 | ||
出力パラメーター | 呼び出し先 | out |
すべての型 |
Windows ランタイムでは、パラメーターとしての動作が多少異なる配列型がサポートされています。
配列 は、連続して格納され、インデックスを介してアクセスされる多数の変数を含むデータ構造です。 配列に含まれる変数 (配列の
MIDL 3.0 では、1 次元配列の宣言がサポートされています。
配列パラメーター は参照型であり、すべての参照型が既定で入力パラメーターと同様です。 その場合、呼び出し元は配列を呼び出し先に割り当てます。この配列は要素を読み取ることができますが、変更することはできません (読み取り専用)。 これは、配列 パターンを渡す ref
キーワードを追加することで、fill 配列 パターンを使用することもできます。その設定では、配列は呼び出し元によって引き続き割り当てられますが、概念的には、呼び出し先が配列要素の値を埋めるという意味での出力パラメーターです。 最後のパターンは、呼び出し先が呼び出し元に返される前に、呼び出し先が引数を割り当て、初期化している
runtimeclass Test
{
// Pass array pattern: read-only array from caller to callee
void PassArray(Int32[] values);
// Fill array pattern: caller allocates array for callee to fill
void FillArray(ref Int32[] values);
// Receive array pattern: callee allocates and fill an array returned to caller
void ReceiveArray(out Int32[] values);
}
次の表は、配列とその要素の動作をまとめたものです。
配列パターン | キーワード | 割り当て者 | 呼び出し先による要素のアクセス |
---|---|---|---|
"配列を渡す" | (なし) | 来客 | 読み取り専用 |
"配列の塗りつぶし" | ref |
来客 | 書き込み専用 |
"配列の受信" | out |
呼び出し先 | 読み取り/書き込み |
C++/WinRT で C スタイルの配列パラメーター (準拠配列とも呼ばれます) を使用する方法の詳細については、「配列パラメーターを参照してください。
静的メソッドとインスタンス メソッド
プレフィックスが付いた static
修飾子で宣言されたメソッドは、静的メソッドです。 静的メソッドは特定のインスタンスにアクセスできないため、クラスの他の静的メンバーにのみ直接アクセスできます。
次の Entity クラスには、静的メンバーとインスタンス メンバーの両方があります。
runtimeclass Entity
{
Int32 SerialNo { get; };
static Int32 GetNextSerialNo();
static void SetNextSerialNo(Int32 value);
}
各 Entity インスタンスには、独自のシリアル番号 (およびおそらくここには示されていないその他の情報) が含まれています。 内部的には、Entity コンストラクター (インスタンス メソッドのようなもの) は、次に使用可能なシリアル番号を使用して新しいインスタンスを初期化します。
SerialNo プロパティは、プロパティ get メソッドを呼び出すインスタンスのシリアル番号 アクセスできます。
オーバーライド可能なメソッドと保護されたメソッド
Windows ランタイム型のすべてのメソッドは実質的に仮想です。 仮想メソッドが呼び出されると、その呼び出しが行われるインスタンスの ランタイム型 によって、呼び出す実際のメソッドの実装が決まります。
メソッドは、派生クラスでオーバーライド overridable
修飾子が含まれている場合、派生クラスによってメソッドをオーバーライドできます。 派生クラスがオーバーライド可能な基底クラス メソッドを実際にオーバーライドするかどうかは、実装によって決まります。メタデータには存在しません。 派生クラスが基底クラス内のメソッドを再宣言した場合、派生クラス メソッドと共に配置される新しいメソッドを、オーバーライドするのではなく宣言します。
インスタンス メソッドの宣言に protected
修飾子が含まれている場合、メソッドは派生クラスにのみ表示されます。
イベント
イベント 宣言は、クラスがイベント ソースであることを指定するメンバーです。 このようなイベント ソースは、デリゲート (特定のシグネチャを持つメソッド) を実装するすべての受信者に通知を提供します。
event
キーワードを使用してイベントを宣言し、その後にデリゲート型名 (必要なメソッド シグネチャを記述) を続けて、イベントの名前を宣言します。 プラットフォームの既存のデリゲート型を使用するイベントの例を次に示します。
runtimeclass Area
{
...
event Windows.UI.Xaml.WindowSizeChangedEventHandler SizeChanged;
...
}
イベント宣言は、2 つのメソッドを暗黙的にクラスに追加します。add メソッド。クライアントが呼び出してソースにイベント ハンドラーを追加し、削除 メソッドを削除します。このメソッドは、クライアントが以前に追加したイベント ハンドラーを削除するために呼び出します。 その他の例を次に示します。
// Instance event with no meaningful payload.
event Windows.Foundation.TypedEventHandler<BasicClass, Object> Changed;
// Instance event with event parameters.
event Windows.Foundation.TypedEventHandler<BasicClass, BasicClassSaveCompletedEventArgs> SaveCompleted;
// Static event with no meaningful payload.
static event Windows.Foundation.EventHandler<Object> ResetOccurred;
// Static event with event parameters.
static event Windows.Foundation.EventHandler<BasicClassDeviceAddedEventArgs> DeviceAdded;
慣例により、2 つのパラメーターが常に Windows ランタイム イベント ハンドラーに渡されます。送信者の ID とイベント引数オブジェクトです。 送信者は、イベントを発生させたオブジェクト、または静的イベントの場合は null です。 イベントに意味のあるペイロードがない場合、イベント引数は値が null である Object です。
デリゲート
デリゲート型 は、特定のパラメーター リストと戻り値の型を持つメソッドを指定します。 イベントの 1 つのインスタンスには、デリゲート型のインスタンスへの任意の数の参照を含めることができます。 宣言は、ランタイム クラスの外部に存在し、delegate
キーワードのプレフィックスが付いている点を除き、通常のメンバー メソッドの宣言と似ています。
デリゲートを使用すると、メソッドを、変数に割り当て、パラメーターとして渡すことができるエンティティとして扱うことができます。 デリゲートは、他の言語で見つかる関数ポインターの概念に似ています。 ただし、関数ポインターとは異なり、デリゲートはオブジェクト指向で型セーフです。
プラットフォームからデリゲート型
delegate void SizeChangedHandler(Object sender, Windows.UI.Core.WindowSizeChangedEventArgs args);
SizeChangedHandler デリゲート型のインスタンスは、2 つの引数 (オブジェクトと WindowSizeChangedEventArgs) を受け取り、void を返す任意のメソッドを参照できます。 構造体
デリゲートの興味深く便利なプロパティは、デリゲートが参照するメソッドのクラスを認識したり、気にしたりしないという点です。重要なのは、参照されるメソッドがデリゲートと同じパラメーターと戻り値の型を持つということです。
必要に応じて、[uuid(...)]
を使用してデリゲート宣言を属性化できます。
HRESULTを返すデリゲート
構造体
構造体 は、データ メンバー (フィールド) を含むことができるデータ構造体です。 ただし、クラスとは異なり、構造体は値型です。
構造体は、値セマンティクスを持つ小さなデータ構造に特に便利です。 複素数(座標系内の点)は、構造体の良い例です。 小さなデータ構造に対してクラスではなく構造体を使用すると、アプリケーションが実行するメモリ割り当ての数に大きな違いが生じます。
例を使用して、クラスと構造体を比較してみましょう。 クラスとして最初に Point のバージョンを次に示します。
runtimeclass Point
{
Point(Int32 x, Int32 y);
Int32 x;
Int32 y;
}
この C# プログラムは、Pointの 100 個のインスタンスの配列を作成して初期化します。 Point クラスとして実装されると、101 個の個別のオブジェクトがインスタンス化されます。配列オブジェクト自体用に 1 つ。100 Point 要素ごとに 1 つ。
class Test
{
static Test()
{
Point[] points = new Point[100];
for (Int32 i = 0; i < 100; ++i) points[i] = new Point(i, i);
}
}
よりパフォーマンスの高い代替手段は、クラスではなく、Point を構造体にすることです。
struct Point
{
Int32 x;
Int32 y;
};
これで、1 つのオブジェクト (配列オブジェクト自体) のみがインスタンス化されます。 Point 要素は、配列内の行に格納されます。プロセッサ キャッシュが強力な効果を発揮するために使用できるメモリ配置。
構造体の変更は、バイナリ破壊的変更です。 そのため、Windows 自体の一部として実装された構造体は、導入後は変更されません。
インターフェイス
インターフェイス は、クラスによって実装できるコントラクトを定義します。 インターフェイスには、クラスと同様に、メソッド、プロパティ、およびイベントを含めることができます。
クラスとは異なり、インターフェイスは定義するメンバーの実装を提供しません。 インターフェイスを実装する任意のクラスによって提供される必要があるメンバーを指定するだけです。
インターフェイス 、他のインターフェイスも実装するために、インターフェイスを実装するクラス 必要になる場合があります。 次の例では、IComboBox
interface IControl
{
void Paint();
}
interface ITextBox requires IControl
{
void SetText(String text);
}
interface IListBox requires IControl
{
void SetItems(String[] items);
}
interface IComboBox requires ITextBox, IListBox
{
...
}
クラスは、0 個以上のインターフェイスを実装できます。 次の例では、EditBox
interface IDataBound
{
void Bind(Binder b);
}
runtimeclass EditBox : IControl, IDataBound
{
}
Windows プラットフォームの Windows ランタイム型の場合、これらの型を使用する開発者がインターフェイスを実装することが期待される場合は、インターフェイスが定義されます。 インターフェイスを定義するためのもう 1 つのユース ケースは、複数のランタイム クラスがインターフェイスを実装し、それらのランタイム クラスを使用する開発者が、その共通インターフェイスを介してさまざまな種類のオブジェクトに一般的に (したがってポリモーフィックに) アクセスする場合です。
手記
MIDL 3.0 で requires
キーワードを使用する方法についてもう一度検討してください。 これは、特にバージョン管理が考慮されている場合に、乱雑な設計につながる可能性があります。
列挙型
列挙型 (または列挙型)は、名前付き定数のセットを持つ個別の値型です。 次の例では、Color という名前の列挙型を定義して使用します。Red、Green、Blueの 3 つの定数値を使用します。
enum Color
{
Red,
Green,
Blue, // Trailing comma is optional, but recommended to make future changes easier.
};
各列挙型には、列挙型の基になる型
Windows ランタイムでは、通常の 列挙型
フラグ列挙型には、[flags]
属性が適用されています。 その場合、列挙型の基になる型は UInt32
[flags]
enum SetOfBooleanValues
{
None = 0x00000000,
Value1 = 0x00000001,
Value2 = 0x00000002,
Value3 = 0x00000004,
};
列挙型のストレージ形式と使用可能な値の範囲は、基になる型によって決まります。 列挙型が受け取ることができる値のセットは、宣言された列挙型メンバーによって制限されません。
次の例では、Alignmentという名前の列挙型 Int32の基になる型を定義します。
enum Alignment
{
Left = -1,
Center = 0,
Right = 1
};
C および C++ の場合も同様に、MIDL 3.0 列挙型には、メンバーの値を指定する定数式を含めることができます (上記参照)。 各列挙型メンバーの定数値は、列挙型の基になる型の範囲内にある必要があります。 列挙型メンバー宣言で値が明示的に指定されていない場合、メンバーには値 0 が与えられます (列挙型の最初のメンバーの場合)、またはテキストの前にある列挙型メンバーの値に 1 を加算します。
次の例では、Permissionsという名前の列挙型を定義し、基になる型 UInt32を指定します。
[flags]
enum Permissions
{
None = 0x0000,
Camera = 0x0001,
Microphone = 0x0002
};
属性
MIDL 3.0 ソース コードの型、メンバー、およびその他のエンティティは、動作の特定の側面を制御する修飾子をサポートします。 たとえば、メソッドのアクセシビリティは、protected
アクセス修飾子を使用して制御されます。 MIDL 3.0 では、ユーザー定義型の宣言情報をプログラム エンティティにアタッチし、実行時にメタデータから取得できるように、この機能を一般化します。
プログラムでは、
次の例では、HelpAttribute 属性を定義します。この属性は、プログラム エンティティに配置して、関連するドキュメントへのリンクを提供できます。 ご覧のように、属性は基本的に構造体型であるため、コンストラクターは含まれていないため、データ メンバーのみが含まれます。
[attributeusage(target_runtimeclass, target_event, target_method, target_property)]
attribute HelpAttribute
{
String ClassUri;
String MemberTopic;
}
属性を適用するには、関連付けられた宣言の直前の角かっこ内に、任意の引数と共に名前を付けます。 属性の名前が Attribute で終わる場合は、属性を参照するときに名前のその部分を省略できます。 たとえば、HelpAttribute 属性は次のように使用できます。
[Help("https://docs.contoso.com/.../BookSku", "BookSku class")]
runtimeclass BookSku : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
[Help("https://docs.contoso.com/.../BookSku_Title", "Title method")]
String Title;
}
同じ属性を複数の宣言に適用するには、その属性の後にスコープ ブロックを使用します。 つまり、属性の直後に、属性が適用される宣言を囲む中かっこが続きます。
runtimeclass Widget
{
[Help("https://docs.contoso.com/.../Widget", "Widget members")]
{
void Display(String text);
void Print();
Single Rate;
}
}
Windows 自体の一部として実装される属性は、通常、Windows.Foundation 名前空間にあります。
最初の例に示すように、属性定義で [attributeusage(<target>)]
属性を使用します。 有効なターゲット値は、target_all
、target_delegate
、target_enum
、target_event
、target_field
、target_interface
、target_method
、target_parameter
、target_property
、target_runtimeclass
、および target_struct
です。 かっこ内に複数のターゲットをコンマで区切って含めることができます。
属性に適用できるその他の属性は、[allowmultiple]
と [attributename("<name>")]
です。
パラメーター化された型
次の例では、エラー MIDL2025が生成されます。[msg]構文エラー [context]: > を想定しています。または、">>"に近い場合です。
Windows.Foundation.IAsyncOperation<Windows.Foundation.Collections.IVector<String>> RetrieveCollectionAsync();
代わりに、テンプレート終了文字のペアが右シフト演算子として誤って解釈されないように、2 つの >
文字の間にスペースを挿入します。
Windows.Foundation.IAsyncOperation<Windows.Foundation.Collections.IVector<String> > RetrieveCollectionAsync();
次の例では、エラー MIDL2025が生成されます:[msg]構文エラー [context]: > を想定しているか、"["付近です。 これは、パラメーター化されたインターフェイスのパラメーター型引数として配列を使用することは無効であるためです。
Windows.Foundation.IAsyncOperation<Int32[]> RetrieveArrayAsync();
解決策については、「非同期的に配列を返す」を参照してください。