プロパティと項目の比較
MSBuild のプロパティと項目の両方を使用することで、タスクに情報を渡したり、条件を評価したりできるだけでなく、プロジェクト ファイルで参照できる値を格納しておくこともできます。
プロパティは名前と値のペアです。 詳細については、「MSBuild プロパティ」を参照してください。
項目は、通常はファイルを表すオブジェクトです。 項目オブジェクトにはメタデータのコレクションを関連付けることができます。 メタデータは名前と値のペアです。 詳細については、「MSBuild 項目」を参照してください。
スカラーとベクター
MSBuild プロパティは文字列値を 1 つだけ含む名前と値のペアなので、スカラーと呼ばれます。 MSBuild 項目の種類は項目リストなので、ベクターと呼ばれます。 ただし、実際には、プロパティが複数の値を表すことや、項目の種類に 0 個または 1 個の項目が含まれることもあります。
ターゲットの依存関係の挿入
プロパティがどのようにして複数の値を表すかを確認するために、ビルドするターゲットのリストにターゲットを追加する一般的な使用パターンについて考えてみます。 このリストは、通常、ターゲット名がセミコロンで区切られているプロパティ値で表されます。
<PropertyGroup>
<BuildDependsOn>
BeforeBuild;
CoreBuild;
AfterBuild
</BuildDependsOn>
</PropertyGroup>
通常、BuildDependsOn プロパティはターゲットの DependsOnTargets 属性の引数として使用され、実質的に項目リストに変換されます。 このプロパティをオーバーライドして、ターゲットを追加するかターゲットの実行順序を変更することができます。 次に例を示します。
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
CustomBuild;
</BuildDependsOn>
</PropertyGroup>
この例では、CustomBuild ターゲットがターゲット リストに追加され、BuildDependsOn に値 BeforeBuild;CoreBuild;AfterBuild;CustomBuild が指定されます。
MSBuild 4.0 以降では、ターゲットの依存関係の挿入は使用されなくなりました。 代わりに、AfterTargets 属性および BeforeTargets 属性を使用してください。 詳細については、「ターゲットのビルド順序」を参照してください。
文字列と項目リストとの変換
MSBuild では、必要に応じて、項目の種類と文字列値との間の変換が実行されます。 項目リストを文字列値に変換する方法を確認するために、項目の種類を MSBuild プロパティの値として使用したときの動作について考えてみます。
<ItemGroup>
<OutputDir Include="KeyFiles\;Certificates\" />
</ItemGroup>
<PropertyGroup>
<OutputDirList>@(OutputDir)</OutputDirList>
</PropertyGroup>
項目の種類 OutputDir には、値が "KeyFiles\;Certificates\" である Include 属性が設定されています。 MSBuild によって、この文字列が KeyFiles\ と Certificates\ の 2 つの項目に解析されます。 項目の種類 OutputDir が OutputDirList プロパティの値として使用されると、MSBuild によって、項目の種類がセミコロン区切りの文字列 "KeyFiles\;Certificates\" に変換 ("平坦化") されます。
タスクにおけるプロパティと項目
プロパティと項目は、MSBuild タスクの入力および出力として使用されます。 詳細については、「MSBuild タスク」を参照してください。
プロパティは属性としてタスクに渡されます。 タスク内では、MSBuild プロパティは、値を文字列との間で変換できるプロパティ型で表されます。 サポートされるプロパティ型には、bool、char、DateTime、Decimal、Double、int、string、および ChangeType で処理できるすべての型があります。
項目は ITaskItem オブジェクトとしてタスクに渡されます。 タスク内では、ItemSpec は項目の値を表し、GetMetadata はそのメタデータを取得します。
項目の種類の項目リストは、ITaskItem オブジェクトの配列として渡すことができます。 .NET Framework 3.5 以降では、Remove 属性を使用してターゲットの項目リストから項目を削除できます。 項目リストから項目を削除できるので、項目の種類に含まれる項目数を 0 にすることができます。 項目リストがタスクに渡されると、タスクのコードでこの可能性がチェックされます。
プロパティと項目の評価順序
ビルドの評価フェーズでは、インポートされたファイルが表示される順にビルドに組み込まれます。 プロパティと項目は、次の順序の 3 つのパスで定義されます。
プロパティが表示される順に定義および変更されます。
項目定義が表示される順に定義および変更されます。
項目が表示される順に定義および変更されます。
ビルドの実行フェーズでは、ターゲット内で定義されたプロパティと項目が、単一フェーズで表示される順に共に評価されます。
ただし、これがすべてではありません。 プロパティ、項目定義、または項目が定義されるときに、その値が評価されます。 式エバリュエーターによって、値を指定する文字列が展開されます。 文字列の展開は、ビルドのフェーズによって異なります。 より詳細なプロパティと項目の評価順序を次に示します。
ビルドの評価フェーズでは、次のように処理が行われます。
プロパティが表示される順に定義および変更されます。 プロパティ関数が実行されます。 $(PropertyName) という形式のプロパティ値が式内で展開されます。 プロパティ値が展開された式に設定されます。
項目定義が表示される順に定義および変更されます。 プロパティ関数は式内で既に展開されています。 メタデータ値が展開された式に設定されます。
項目の種類が表示される順に定義および変更されます。 @(ItemType) という形式の項目値が展開されます。 項目の変換も展開されます。 プロパティ関数とプロパティ値は式内で既に展開されています。 項目リストとメタデータ値が展開された式に設定されます。
ビルドの実行フェーズでは、次のように処理が行われます。
- ターゲット内で定義されたプロパティと項目が、表示される順に共に評価されます。 プロパティ関数が実行され、プロパティ値が式内で展開されます。 項目値と項目の変換も展開されます。 プロパティ値、項目の種類の値、およびメタデータ値が展開された式に設定されます。
評価順序の軽度の影響
ビルドの評価フェーズでは、プロパティの評価が項目の評価よりも先に実行されます。 ただし、プロパティには、項目値によって決まると思われる値が指定されることがあります。 次のようなスクリプトがあるとします。
<ItemGroup>
<KeyFile Include="KeyFile.cs">
<Version>1.0.0.3</Version>
</KeyFile>
</ItemGroup>
<PropertyGroup>
<KeyFileVersion>@(KeyFile->'%(Version)')</KeyFileVersion>
</PropertyGroup>
<Target Name="AfterBuild">
<Message Text="KeyFileVersion: $(KeyFileVersion)" />
</Target>
Message タスクを実行すると、次のメッセージが表示されます。
KeyFileVersion: 1.0.0.3
これは、KeyFileVersion の値が実際には文字列 "@(KeyFile->'%(Version)')" であるためです。 項目と項目の変換は、プロパティを最初に定義したときには展開されていないので、KeyFileVersion プロパティには展開されていない文字列の値が割り当てられています。
ビルドの実行フェーズで、Message タスクの処理時に、MSBuild によって文字列 "@(KeyFile->'%(Version)')" が展開されて "1.0.0.3" が取得されます。
プロパティ グループと項目グループの順序が逆の場合でも、同じメッセージが表示されます。
2 番目の例として、プロパティ グループと項目グループがターゲット内に配置されている場合の動作について考えてみます。
<Target Name="AfterBuild">
<PropertyGroup>
<KeyFileVersion>@(KeyFile->'%(Version)')</KeyFileVersion>
</PropertyGroup>
<ItemGroup>
<KeyFile Include="KeyFile.cs">
<Version>1.0.0.3</Version>
</KeyFile>
</ItemGroup>
<Message Text="KeyFileVersion: $(KeyFileVersion)" />
</Target>
Message タスクを実行すると、次のメッセージが表示されます。
KeyFileVersion:
これは、ビルドの実行フェーズでは、ターゲット内で定義されたプロパティ グループと項目グループが上から順に同時に評価されるためです。 KeyFileVersion が定義された時点では、KeyFile は不明です。 したがって、項目の変換は空の文字列に展開されます。
この場合、プロパティ グループと項目グループの順序を逆にすると、元のメッセージが復元されます。
<Target Name="AfterBuild">
<ItemGroup>
<KeyFile Include="KeyFile.cs">
<Version>1.0.0.3</Version>
</KeyFile>
</ItemGroup>
<PropertyGroup>
<KeyFileVersion>@(KeyFile->'%(Version)')</KeyFileVersion>
</PropertyGroup>
<Message Text="KeyFileVersion: $(KeyFileVersion)" />
</Target>
KeyFileVersion の値は、"@(KeyFile->'%(Version)')" ではなく "1.0.0.3" に設定されます。 Message タスクを実行すると、次のメッセージが表示されます。
KeyFileVersion: 1.0.0.3