csprojに条件式を書いて、nugetパッケージを参照したりしなかったりを切り替える

もくじ
https://tera1707.com/entry/2022/02/06/144447

やりたいこと

Moqというnugetパッケージを使っているのだが、 そのMoqのパッケージについて、条件を付けて、

  • 通常時は、Moqを参照しない
  • 条件付きコンパイルシンボルに特定の文字列を書いたときだけ、Moqを参照する

ということをしたい。

前提

  • VisualStudio2022
  • .NET6
  • C#コンソールアプリで実験
  • 2023/4月時点に実験実施

結論

上の「やりたいこと」で書いた内容については、

  • 条件付きコンパイルシンボルにシンボルを書くのをやめて、
  • Configuration(DEBUGとかReleaseとかのやつ)に、Moq用のコンフィグを追加して、
  • ビルド時にConfigurationがそのMoq用のコンフィグだったら、
  • Moqのnugetパッケージを参照する

というようにした。

やりかた/やれること

以下に、その結論に達するまでに調べた内容をメモしておく。

csprojは、最初に一回設定したらあとはめったにいじらないモノ、というイメージだったが、実はいろいろできることを知った。

Debugビルド時だけ、nugetパッケージをリンクする

Debugビルド時だけ、Moqのnugetパッケージを使い、Moq(ダミー)の動作をさせたいときなどに使う。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

    <ItemGroup >
        <PackageReference Condition="'$(Configuration)'=='DEBUG'"  Include="Moq" Version="4.18.4" />
    </ItemGroup>
</Project>

csprojで使うプロパティを、ビルド時に文字列を出力してデバッグする

  • 先頭のProject要素にInitialTargets="Test"を入れて、
  • 下記のように<Target Name="Test">と、<Message>を入れる。
<Project Sdk="Microsoft.NET.Sdk" InitialTargets="Test">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
    
    <Target Name="Test">
        <Message Text="Project File Name = $(MSBuildProjectFile)" Importance="High"/>
        <Message Text="Project Extension = $(MSBuildProjectExtension)" Importance="High"/>
    </Target>
</Project>

要素内のconditionに、メソッドを使う

下記の例だと、「条件付きコンパイルシンボル」に「MySymbol」というのを定義しているかどうかをMessageで出している。

条件付きコンパイルシンボルというのはコレ↓のこと。

<Project Sdk="Microsoft.NET.Sdk" InitialTargets="Test">

    <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <Configurations>Debug;Release</Configurations>
    </PropertyGroup>

    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DefineConstants>MySymbol</DefineConstants>
    </PropertyGroup>

    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <DefineConstants>MySymbol</DefineConstants>
    </PropertyGroup>

    <Target Name="Test">
        <Message Text="Debug? = $(DefineConstants.Contains(`MySymbol`))" Importance="High" />
    </Target>
</Project>

DefineConstantsが文字列のプロパティだから、stringがもつContainsメソッドが使えるっぽい。

※最初、条件付きコンパイルシンボルに特定のシンボルを書いたときだけ、あるnugetパッケージを参照するようにしたい、と考えていたが、それよりも、上の方でやっているようにDebug/Releaseに加えてもうひとつConfigurationを作って、そのConditionの名前を、「Condition="'$(Configuration)'=='DEBUG2'"」 みたいな感じで判定してあげた方が見る人がわかりやすそう。(そういう設定があるのが目で見えるので。)

要素内のconditionに、メソッドを使う その2

下記の例では、正規表現を扱うRegexクラスを、csprojの中で使う例が紹介されている。

https://learn.microsoft.com/ja-jp/visualstudio/msbuild/msbuild-conditional-constructs?view=vs-2022#example

※気力が切れたので未確認。いざそういうことしたくなったら調べてみる。

参考

csprojの中でつかう変数

https://learn.microsoft.com/ja-jp/visualstudio/msbuild/msbuild-reserved-and-well-known-properties?view=vs-2022 https://learn.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-properties?view=vs-2022

csprojで条件式を書く方法

https://learn.microsoft.com/ja-jp/visualstudio/msbuild/msbuild-conditional-constructs?view=vs-2022

要素の一覧(ItemGroupとか)

https://learn.microsoft.com/ja-jp/visualstudio/msbuild/msbuild-project-file-schema-reference?view=vs-2022

SDKの要素?(TargetFrameworkとか)

https://learn.microsoft.com/ja-jp/dotnet/core/project-sdk/msbuild-props#framework-properties

csprojの条件分けの書き方、参考になりそう

https://atmarkit.itmedia.co.jp/fdotnet/special/msbuild02/msbuild02_02.html

csprojの要素を自前で作れるらしい

https://atmarkit.itmedia.co.jp/fdotnet/special/msbuild02/msbuild02_03.html

csprojの中でデバッグのために文字列を出力する

https://learn.microsoft.com/ja-jp/visualstudio/msbuild/walkthrough-using-msbuild?view=vs-2022