屬性函式

屬性函式是呼叫 MSBuild 屬性定義中顯示的 .NET 方法。 與工作不同,屬性函式可用於目標外部。 每當屬性或項目展開時,就會評估屬性函式。 因此,針對任何目標外部的屬性何項目,會在執行任何目標之前,先進行評估。 針對目標內的屬性群組和項目群組,評估目標時會評估屬性函式。

在不使用 MSBuild 工作的情況下,您可以讀取系統時間、比較字串、比對規則運算式,以及執行組建指令碼中的其他動作。 MSBuild 會嘗試將字串轉換為數字或將數字轉換為字串,並視需要進行其他轉換。

從屬性函式傳回的字串值具有逸出的特殊字元。 如果您想要將值視為直接放入專案檔中,請使用 $([MSBuild]::Unescape()) 來取消逸出特殊字元。

屬性函式語法

以下是三種類型的屬性函式;每一種函式都具有不同的語法:

  • 字串 (執行個體) 屬性函式
  • 靜態屬性函式
  • MSBuild 屬性函式

字串屬性函式

所有建置屬性值都是字串值。 您可以使用字串 (執行個體) 方法操作任何屬性值。 例如,您可以使用下列程式碼,從代表完整路徑的建置屬性,擷取磁碟機名稱 (前三個字元):

$(ProjectOutputFolder.Substring(0,3))

靜態屬性函式

在您的組建指令碼中,您可以存取許多系統類別的靜態屬性和方法。 若要取得靜態屬性的值,請使用下列語法,其中 Class 是系統類別的名稱,而 Property 是屬性的名稱。

$([Class]::Property)

例如,您可以使用下列程式碼,將建置屬性設為目前的日期和時間。

<Today>$([System.DateTime]::Now)</Today>

若要呼叫靜態方法,請使用下列語法,其中 Class 是系統類別的名稱、Method 是方法的名稱,而 ((Parameters)) 是方法的參數清單:

$([Class]::Method(Parameters))

例如,若要將建置屬性設為新的 GUID,您可以使用下列指令碼:

<NewGuid>$([System.Guid]::NewGuid())</NewGuid>

在靜態屬性函式中,您可以使用以下系統類別的公用靜態方法或屬性:

此外,您可以使用下列靜態方法和屬性:

System.OperatingSystem 屬性函式

System.OperatingSystem 屬性函式會傳回 MSBuild 執行所在的作業系統相關資訊。 例如,如果您的專案是以 Linux 為目標並建置於 macOS,則屬性函式會傳回 macOS 相關資訊。

在 .NET 上執行的 MSBuild 中 (dotnet build),System.OperatingSystem 類別的所有靜態方法都可以作為靜態屬性函式呼叫。

在 .NET Framework 上執行的 MSBuild 中 (MSBuild.exe),只有 System.OperatingSystem 的下列方法可以作為靜態屬性函式呼叫。 MSBuild 會在內部實作這些方法,因為 System.OperatingSystem 不會在 .NET Framework 上定義它們。 無法呼叫沒有 .NET SDK 的作業系統方法,例如 System.OperatingSystem::IsTvOS

下列範例示範這些屬性函式的使用方式。

<IsWindows>$([System.OperatingSystem]::IsWindows())</IsWindows>

在靜態屬性上呼叫執行個體方法

如果您存取的靜態屬性傳回物件執行個體,您就可以叫用該物件的執行個體方法。 若要叫用執行個體方法,請使用下列語法,其中 Class 是系統類別的名稱、Property 是屬性的名稱、Method 是方法的名稱,而 ((Parameters)) 是方法的參數清單:

$([Class]::Property.Method(Parameters))

類別的名稱必須是命名空間的完整名稱。

例如,您可以使用下列程式碼,將建置屬性設為目前日期的今天。

<Today>$([System.DateTime]::Now.ToString('yyyy.MM.dd'))</Today>

MSBuild 屬性函式

您組建中的數個靜態方法可以存取來提供算術、位元邏輯和逸出字元支援。 您可以使用下列語法存取這些方法,其中 Method 是方法的名稱,而 ((Parameters)) 是方法的參數清單。

$([MSBuild]::Method(Parameters))

例如,若要將兩個具有數值的屬性加在一起,請使用下列程式碼。

$([MSBuild]::Add($(NumberOne), $(NumberTwo)))

以下是 MSBuild 屬性函式的清單:

函式簽章 描述
double Add(double a, double b) 將兩個雙精度浮點數相加。
long Add(long a, long b) 將兩個長整數相加。
double Subtract(double a, double b) 將兩個雙精度浮點數相減。
long Subtract(long a, long b) 將兩個長整數相減。
double Multiply(double a, double b) 將兩個雙精度浮點數相乘。
long Multiply(long a, long b) 將兩個長整數相乘。
double Divide(double a, double b) 將兩個雙精度浮點數相除。
long Divide(long a, long b) 將兩個長整數相除。
double Modulo(double a, double b) 對兩個雙精度浮點數進行模數運算。
long Modulo(long a, long b) 對兩個長整數進行模數運算。
string Escape(string unescaped) 根據 MSBuild 逸出規則逸出字串。
string Unescape(string escaped) 根據 MSBuild 逸出規則取消逸出字串。
int BitwiseOr(int first, int second) 對第一和第二個整數 (第一 | 第二) 執行位元 OR
int BitwiseAnd(int first, int second) 對第一和第二個整數 (第一 & 第二) 執行位元 AND
int BitwiseXor(int first, int second) 對第一和第二個整數 (第一 ^ 第二) 執行位元 XOR
int BitwiseNot(int first) 執行位元 NOT (~第一)。
bool IsOsPlatform(string platformString) 指定目前的作業系統平台是否為 platformStringplatformString 必須是 OSPlatform 的成員。
bool IsOSUnixLike() 如果目前的作業系統是 UNIX 系統,則為 true。
string NormalizePath(params string[] path) 取得所提供路徑的規範化完整路徑,並確保它包含目前作業系統的正確目錄分隔符號字元。
string NormalizeDirectory(params string[] path) 取得所提供目錄的規範化完整路徑,並確保它包含目前作業系統的正確目錄分隔符號字元,且後面有斜線。
string EnsureTrailingSlash(string path) 如果指定的路徑後面沒有斜線,請新增一個。 如果此路徑是空字串,請不要修改它。
string GetPathOfFileAbove(string file, string startingDirectory) 搜尋並傳回目錄結構中檔案的完整路徑,位於目前建置檔案的位置上,或根據 startingDirectory (若指定)。
string GetDirectoryNameOfFileAbove(string startingDirectory, string fileName) 在指定的目錄中,或在該目錄上方目錄結構中的位置中找到檔案,並傳回檔案的目錄。
string MakeRelative(string basePath, string path) path 成為 basePath 的相對項。 basePath 必須是絕對目錄。 如果 path 不能成為相對的,它就會被逐字傳回。 類似於 Uri.MakeRelativeUri
string ValueOrDefault(string conditionValue, string defaultValue) 只有在參數 conditionValue 是空的時,才會傳回參數 defaultValue 中的字串,否則傳回 conditionValue 的值。
string ConvertToBase64(string toEncode) 將所有位元組轉換成 base 64 之後,傳回字串 (英數位元加上 +/),結尾為一或兩個 =
string ConvertFromBase64(string toDecode) 將 base 64 進行轉換之後,傳回字串 (英數位元加上 +/),結尾為一或兩個 =

巢狀屬性函式

您可以組合屬性函式,以構成較複雜的函式,如下列範例所示:

$([MSBuild]::BitwiseAnd(32, $([System.IO.File]::GetAttributes(tempFile))))

這個範例會傳回 FileAttributes 的值。tempFile 路徑所指定檔案的 Archive 位元 (32 或 0)。 請注意,列舉資料值無法依某些內容中的名稱顯示。 在上一個範例中,必須改為使用數值 (32)。 在其他情況下,依據所呼叫方法的預期,必須使用列舉資料值。 在下列範例中,列舉值為 RegexOptions。必須使用 ECMAScript,因為無法如這個方法預期轉換數值。

<PropertyGroup>
    <GitVersionHeightWithOffset>$([System.Text.RegularExpressions.Regex]::Replace("$(PrereleaseVersion)", "^.*?(\d+)$", "$1", "System.Text.RegularExpressions.RegexOptions.ECMAScript"))</GitVersionHeightWithOffset>
</PropertyGroup>

中繼資料也可能會出現在巢狀屬性函式中。 如需詳細資訊,請參閱批次處理

MSBuild DoesTaskHostExist

MSBuild 中的 DoesTaskHostExist 屬性函式會傳回目前是否已為指定執行階段和架構值安裝工作主機。

此屬性函式具有下列語法:

$([MSBuild]::DoesTaskHostExist(string theRuntime, string theArchitecture))

MSBuild EnsureTrailingSlash

MSBuild 中的 EnsureTrailingSlash 屬性函式會加上尾端斜線 (如果原本沒有的話)。

此屬性函式具有下列語法:

$([MSBuild]::EnsureTrailingSlash('$(PathProperty)'))

MSBuild GetDirectoryNameOfFileAbove

MSBuild GetDirectoryNameOfFileAbove 屬性函式會向上搜尋包含指定檔案的目錄,從指定目錄開始 (含)。 如果找到檔案,則會傳回最接近目錄 (包含檔案) 的完整路徑,否則會傳回空字串。

此屬性函式具有下列語法:

$([MSBuild]::GetDirectoryNameOfFileAbove(string startingDirectory, string fileName))

此範例示範如何僅在找到相符項目時,在目前資料夾中或上方匯入最接近的 EnlistmentInfo.props 檔案:

<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), EnlistmentInfo.props))\EnlistmentInfo.props" Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), EnlistmentInfo.props))' != '' " />

請注意,您可以改用 GetPathOfFileAbove 函式,更簡潔地撰寫此範例:

<Import Project="$([MSBuild]::GetPathOfFileAbove(EnlistmentInfo.props))" Condition=" '$([MSBuild]::GetPathOfFileAbove(EnlistmentInfo.props))' != '' " />

MSBuild GetPathOfFileAbove

MSBuild GetPathOfFileAbove 屬性函式會向上搜尋包含指定檔案的目錄,從指定目錄開始 (含)。 如果找到檔案,則會傳回最接近相符檔案的完整路徑,否則會傳回空字串。

此屬性函式具有下列語法:

$([MSBuild]::GetPathOfFileAbove(string file, [string startingDirectory]))

其中 file 是要搜尋檔案的名稱,而 startingDirectory 是啟動搜尋的選擇性目錄。 根據預設,會從目前檔案的自有目錄中開始搜尋。

此範例示範如何僅在找到相符項目時,在目前目錄中或上方匯入名為 dir.props 的檔案:

<Import Project="$([MSBuild]::GetPathOfFileAbove(dir.props))" Condition=" '$([MSBuild]::GetPathOfFileAbove(dir.props))' != '' " />

在功能上相當於

<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))' != '' " />

不過,有時候您需要在父目錄中開始搜尋,以避免比對目前的檔案。 此範例示範 Directory.Build.props 檔案如何匯入最接近的 Directory.Build.props 檔案,而不遞迴地將檔案本身匯入:

<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />

在功能上相當於

<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove('$(MSBuildThisFileDirectory)../', 'Directory.Build.props'))/Directory.Build.props" />

MSBuild GetRegistryValue

MSBuild GetRegistryValue 屬性函式會傳回登錄機碼的值。 此函式採用兩個引數 (機碼名稱和值名稱),並傳回登錄的值。 如果您未指定值名稱,則會傳回預設值。

下列範例顯示如何使用此函式:

$([MSBuild]::GetRegistryValue(`HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\10.0\Debugger`, ``))                                  // default value
$([MSBuild]::GetRegistryValue(`HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\10.0\Debugger`, `SymbolCacheDir`))
$([MSBuild]::GetRegistryValue(`HKEY_LOCAL_MACHINE\SOFTWARE\(SampleName)`, `(SampleValue)`))             // parens in name and value

警告

在 MSBuild (dotnet build) 的 .NET SDK 版本中,不支援此函式。

MSBuild GetRegistryValueFromView

如果提供登錄機碼、值和一或多個已排序登錄檢視,MSBuild GetRegistryValueFromView 屬性函式會取得系統登錄資料。 在每一個登錄檢視中會按順序搜尋機碼和值,直到找到它們。

此屬性函式的語法為:

[MSBuild]::GetRegistryValueFromView(string keyName, string valueName, object defaultValue, params object[] views)

Windows 64 位元作業系統會維護 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node 登錄機碼,此登錄機碼會呈現 32 位元應用程式的 HKEY_LOCAL_MACHINE\SOFTWARE 登錄檢視。

根據預設,在 WOW64 上執行的 32 位元應用程式會存取 32 位元登錄檢視,而 64 位元應用程式會存取 64 位元登錄檢視。

下列登錄檢視皆可使用:

登錄檢視 定義
RegistryView.Registry32 32 位元應用程式登錄檢視。
RegistryView.Registry64 64 位元應用程式登錄檢視。
RegistryView.Default 符合應用程式執行所在之處理序的登錄檢視。

以下是一個範例。

$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Silverlight\v3.0\ReferenceAssemblies', 'SLRuntimeInstallPath', null, RegistryView.Registry64, RegistryView.Registry32))

取得 ReferenceAssemblies 機碼的 SLRuntimeInstallPath 資料,首先在 64 位元登錄檢視中尋找,然後在 32 位元登錄檢視中尋找。

警告

在 MSBuild (dotnet build) 的 .NET SDK 版本中,不支援此函式。

MSBuild MakeRelative

MSBuild MakeRelative 屬性函式會傳回與第一個路徑相對之第二個路徑的相對路徑。 每一個路徑都可以是檔案或資料夾。

此屬性函式具有下列語法:

$([MSBuild]::MakeRelative($(FileOrFolderPath1), $(FileOrFolderPath2)))

下列程式碼是此語法的範例。

<PropertyGroup>
    <Path1>c:\users\</Path1>
    <Path2>c:\users\username\</Path2>
</PropertyGroup>

<Target Name = "Go">
    <Message Text ="$([MSBuild]::MakeRelative($(Path1), $(Path2)))" />
    <Message Text ="$([MSBuild]::MakeRelative($(Path2), $(Path1)))" />
</Target>

<!--
Output:
   username\
   ..\
-->

MSBuild StableStringHash

MSBuild StableStringHash 屬性函式接受字串引數,並傳回保證穩定的雜湊程式碼,這表示對於相同的字串輸入始終傳回相同的程式碼。 無論使用 MSBuild 或 dotnet build,傳回的雜湊值都是相同的,並且在跨平台架構上是穩定的,這與 .NET 方法 GetHashCode 不同。 不保證它在不同的 MSBuild 版本中保持穩定。

此函式在 MSBuild 16.9.0 或更高版本中可用。

下列範例顯示如何使用此函式。

<Project>
   <PropertyGroup>
      <MyHash>$([MSBuild]::StableStringHash("test1"))</MyHash>
   </PropertyGroup>

   <Target Name="WriteHash" AfterTargets="Build">
      <Message Text="Hash: $(MyHash)"/>
   </Target>
</Project>

從 MSBuild 版本 17.10.0 開始,此函數接受第二個選擇性引數,請求使用雜湊演算法:

<Project>
   <PropertyGroup>
      <MyHash>$([MSBuild]::StableStringHash("test1", "Sha256"))</MyHash>
   </PropertyGroup>

   <Target Name="WriteHash" AfterTargets="Build">
      <Message Text="Hash: $(MyHash)"/>
   </Target>
</Project>

第二個選擇性引數不區分大小寫,目前支援下列值:

  • 舊版 - 保留與呼叫函式相同的行為,而不使用第二個引數。 傳回帶正負號的 32 位元整數,其屬性與 string.GetHashCode 類似。
  • Fnv1a32bit - 傳回帶正負號的 32 位元整數,表示給定字串之 Fowler–Noll–Vo 雜湊版本 '1a' 雜湊值。
  • Fnv1a64bit - 傳回帶正負號的 64 位元整數,表示給定字串之 Fowler–Noll–Vo 雜湊版本 '1a' 雜湊值。
  • Sha256 - 傳回無前置詞十六進位字串,表示給定字串的 SHA256 雜湊值。

MSBuild ValueOrDefault

MSBuild ValueOrDefault 屬性函式會傳回第一個引數,除非它是 null 或空白。 如果第一個引數是 null 或空白,函式會傳回第二個引數。

下列範例顯示如何使用此函式。

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <PropertyGroup>
        <Value1>$([MSBuild]::ValueOrDefault('$(UndefinedValue)', 'a'))</Value1>
        <Value2>$([MSBuild]::ValueOrDefault('b', '$(Value1)'))</Value2>
    </PropertyGroup>

    <Target Name="MyTarget">
        <Message Text="Value1 = $(Value1)" />
        <Message Text="Value2 = $(Value2)" />
    </Target>
</Project>

<!--
Output:
  Value1 = a
  Value2 = b
-->

MSBuild TargetFramework 和 TargetPlatform 函式

MSBuild 16.7 和更新版本會定義數個函式來處理 TargetFramework 和 TargetPlatform 屬性

函式簽章 描述
GetTargetFrameworkIdentifier(string targetFramework) 從 TargetFramework 剖析 TargetFrameworkIdentifier。
GetTargetFrameworkVersion(string targetFramework, int versionPartCount) 從 TargetFramework 剖析 TargetFrameworkVersion。
GetTargetPlatformIdentifier(string targetFramework) 從 TargetFramework 剖析 TargetPlatformIdentifier。
GetTargetPlatformVersion(string targetFramework, int versionPartCount) 從 TargetFramework 剖析 TargetPlatformVersion。
IsTargetFrameworkCompatible(string targetFrameworkTarget, string targetFrameworkCandidate) 如果候選目標 Framework (第二個引數) 與第一個引數所指示的目標 Framework 相容,則傳回 'True',否則傳回 false。

GetTargetFrameworkVersionGetTargetPlatformVersionversionPartCount 參數預設值為 2。

下列範例顯示如何使用這些函式。

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <PropertyGroup>
        <Value1>$([MSBuild]::GetTargetFrameworkIdentifier('net5.0-windows7.0'))</Value1>
        <Value2>$([MSBuild]::GetTargetFrameworkVersion('net5.0-windows7.0'))</Value2>
        <Value3>$([MSBuild]::GetTargetPlatformIdentifier('net5.0-windows7.0'))</Value3>
        <Value4>$([MSBuild]::GetTargetPlatformVersion('net5.0-windows7.0'))</Value4>
        <Value5>$([MSBuild]::IsTargetFrameworkCompatible('net5.0-windows', 'net5.0'))</Value5>
        <Value6>$([MSBuild]::IsTargetFrameworkCompatible('net5.0', 'net6.0'))</Value6>
        <Value7>$([MSBuild]::IsTargetFrameworkCompatible('net5.0', 'net8.0'))</Value7>
    </PropertyGroup>

    <Target Name="MyTarget">
        <Message Text="Value1 = $(Value1)" />
        <Message Text="Value2 = $(Value2)" />
        <Message Text="Value3 = $(Value3)" />
        <Message Text="Value4 = $(Value4)" />
        <Message Text="Value5 = $(Value5)" />
        <Message Text="Value6 = $(Value6)" />
        <Message Text="Value7 = $(Value7)" />
    </Target>
</Project>
Value1 = .NETCoreApp
Value2 = 5.0
Value3 = windows
Value4 = 7.0
Value5 = True
Value6 = False
Value7 = False

MSBuild 版本比較函式

MSBuild 16.5 和更高版本會定義數個函式來比較代表版本的字串。

注意

條件中的比較運算子可以比較可剖析為 System.Version 物件的字串,但比較可能會產生非預期的結果。 偏好屬性函式。

函式簽章 描述
VersionEquals(string a, string b) 根據下列規則,如果 ab 版本相等,則傳回 true
VersionGreaterThan(string a, string b) 根據下列規則,如果 a 版本大於 b ,則傳回 true
VersionGreaterThanOrEquals(string a, string b) 根據下列規則,如果 a 版本大於或等於 b ,則傳回 true
VersionLessThan(string a, string b) 根據下列規則,如果 a 版本小於 b ,則傳回 true
VersionLessThanOrEquals(string a, string b) 根據下列規則,如果 a 版本小於或等於 b ,則傳回 true
VersionNotEquals(string a, string b) 根據下列規則,如果 ab 版本相等,則傳回 false

在這些方法中,版本會剖析為類似 System.Version,但有下列例外狀況:

  • 會忽略前置 vV,這允許與 $(TargetFrameworkVersion) 進行比較。

  • 會忽略從第一個「-」或「+」到版本字串結尾的所有項目。 這允許傳入語意版本 (SemVer),不過順序與 SemVer 不同。 相反地,發行前指定名稱和建置中繼資料沒有任何排序加權。 例如,若要開啟 >= x.y 的功能,並使其開始 x.y.z-pre,這非常有用。

  • 未指定的組件與零值組件相同。 (x == x.0 == x.0.0 == x.0.0.0)。

  • 整數元件中不允許空白字元。

  • 僅主要版本時才有效 (3 等於 3.0.0.0)

  • + 不允許為整數元件的正號 (其會視為 SemVer 中繼資料並予以忽略)

提示

TargetFramework 屬性的比較通常應該使用 IsTargetFrameworkCompatible,而不是擷取及比較版本。 這可讓您比較 TargetFramework,及在 TargetFrameworkIdentifier 與版本有所不同。

MSBuild 條件函式

函式 ExistsHasTrailingSlash 不是屬性函式。 其可與 Condition 屬性搭配使用。 請參閱 MSBuild 條件