csprojに書く設定とdotnet publishに渡すパラメータの実験と比較

tera1707.com

やりたいこと

VisualStudioでビルドしたものと、dotnet publishでビルドしたものの、どちらを最終成果物として使えばよいか?がわかならなかった。

Microsoftの公式ページを見ても、はっきりわかる情報が見つけられないので、いろいろ試してなんとなくどれ使うかを納得したうえで決めたい。

とりあえず、VSでビルドしたときにできるものは、csprojの中に書いてある設定が反映されていて、dotnet publishで出来上がるものにはそれに渡したオプションが反映されてるっぽいので、その2つをいろいろ試してみる。

csprojの各種項目

まず、VisualStudio2022でDebugビルドをしたときに、bin\x64\Debugの下になにができるかを見てみる。

実験で、nugetのMicrosoft.Toolkit.Uwp.Notificationsのパッケージを使い、トーストを出すアプリを使ったので、ターゲットフレームワークWindowsのバージョンが指定されている。(その状態を、今回の標準とする。)

標準

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework>
    <Platforms>x64</Platforms>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\UnitTestJikken\UnitTestJikken.csproj" />
  </ItemGroup>
</Project>

ビルドすると、
こういうフォルダとなかみができる

└─net6.0-windows10.0.17763.0
    │  ConsoleApp1.deps.json
    │  ConsoleApp1.dll
    │  ConsoleApp1.exe
    │  ConsoleApp1.pdb
    │  ConsoleApp1.runtimeconfig.json
    │  Microsoft.Toolkit.Uwp.Notifications.dll
    │  Microsoft.Win32.SystemEvents.dll
    │  Microsoft.Windows.SDK.NET.dll
    │  System.Drawing.Common.dll
    │  UnitTestJikken.dll
    │  UnitTestJikken.pdb
    │  WinRT.Runtime.dll
    │  
    ├─ref
    │      ConsoleApp1.dll
    │      
    └─runtimes
        ├─unix
        │  └─lib
        │      └─netcoreapp3.0
        │              System.Drawing.Common.dll
        │              
        └─win
            └─lib
                └─netcoreapp3.0
                        Microsoft.Win32.SystemEvents.dll
                        System.Drawing.Common.dll

RuntimeIdentifierを指定

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework>
    <Platforms>x64</Platforms>
    ★<SelfContained>false</SelfContained>
    ★<RuntimeIdentifier>win-x64</RuntimeIdentifier>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\UnitTestJikken\UnitTestJikken.csproj" />
  </ItemGroup>
</Project>

RuntimeIdentifierを書くと、こうなる。
※RuntimeIdentifierをtrueにすると、デフォでSelfContainedがtrueになるので、手動でSelfContainedはfalseにして試した

→成果物がRIDフォルダの下に入って、
 runtimeフォルダがなくなる(RID指定したからruntime不要になったということか)

├─net6.0-windows10.0.17763.0
│  └─win-x64
│      │  ConsoleApp1.deps.json
│      │  ConsoleApp1.dll
│      │  ConsoleApp1.exe
│      │  ConsoleApp1.pdb
│      │  ConsoleApp1.runtimeconfig.json
│      │  Microsoft.Toolkit.Uwp.Notifications.dll
│      │  Microsoft.Win32.SystemEvents.dll
│      │  Microsoft.Windows.SDK.NET.dll
│      │  System.Drawing.Common.dll
│      │  UnitTestJikken.dll
│      │  UnitTestJikken.pdb
│      │  WinRT.Runtime.dll
│      │  
│      └─ref
│              ConsoleApp1.dll

RuntimeIdentifierを指定、SelfContainedも指定

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework>
    <Platforms>x64</Platforms>
      <SelfContained>true</SelfContained>
      <RuntimeIdentifier>win-x64</RuntimeIdentifier>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\UnitTestJikken\UnitTestJikken.csproj" />
  </ItemGroup>
</Project>

SelfContainedを指定すると、.net6のランタイム(PCにランタイムがなくても動けるようにするためのもの)のファイル一式が入る。

├─net6.0-windows10.0.17763.0
│  └─win-x64
│      │  api-ms-win-core-console-l1-1-0.dll
│      │  api-ms-win-core-console-l1-2-0.dll
│      │  api-ms-win-core-datetime-l1-1-0.dll
│      │  api-ms-win-core-debug-l1-1-0.dll
│      │  api-ms-win-core-errorhandling-l1-1-0.dll
│      │  api-ms-win-core-file-l1-1-0.dll
│      │  api-ms-win-core-file-l1-2-0.dll
│      │  api-ms-win-core-file-l2-1-0.dll
│      │  api-ms-win-core-handle-l1-1-0.dll
│      │  api-ms-win-core-heap-l1-1-0.dll
│      │  api-ms-win-core-interlocked-l1-1-0.dll
│      │  api-ms-win-core-libraryloader-l1-1-0.dll
│      │  api-ms-win-core-localization-l1-2-0.dll
│      │  api-ms-win-core-memory-l1-1-0.dll
│      │  api-ms-win-core-namedpipe-l1-1-0.dll
│      │  api-ms-win-core-processenvironment-l1-1-0.dll
│      │  api-ms-win-core-processthreads-l1-1-0.dll
│      │  api-ms-win-core-processthreads-l1-1-1.dll
│      │  api-ms-win-core-profile-l1-1-0.dll
│      │  api-ms-win-core-rtlsupport-l1-1-0.dll
│      │  api-ms-win-core-string-l1-1-0.dll
│      │  api-ms-win-core-synch-l1-1-0.dll
│      │  api-ms-win-core-synch-l1-2-0.dll
│      │  api-ms-win-core-sysinfo-l1-1-0.dll
│      │  api-ms-win-core-timezone-l1-1-0.dll
│      │  api-ms-win-core-util-l1-1-0.dll
│      │  api-ms-win-crt-conio-l1-1-0.dll
│      │  api-ms-win-crt-convert-l1-1-0.dll
│      │  api-ms-win-crt-environment-l1-1-0.dll
│      │  api-ms-win-crt-filesystem-l1-1-0.dll
│      │  api-ms-win-crt-heap-l1-1-0.dll
│      │  api-ms-win-crt-locale-l1-1-0.dll
│      │  api-ms-win-crt-math-l1-1-0.dll
│      │  api-ms-win-crt-multibyte-l1-1-0.dll
│      │  api-ms-win-crt-private-l1-1-0.dll
│      │  api-ms-win-crt-process-l1-1-0.dll
│      │  api-ms-win-crt-runtime-l1-1-0.dll
│      │  api-ms-win-crt-stdio-l1-1-0.dll
│      │  api-ms-win-crt-string-l1-1-0.dll
│      │  api-ms-win-crt-time-l1-1-0.dll
│      │  api-ms-win-crt-utility-l1-1-0.dll
│      │  clretwrc.dll
│      │  clrjit.dll
│      │  ConsoleApp1.deps.json
│      │  ConsoleApp1.dll
│      │  ConsoleApp1.exe
│      │  ConsoleApp1.pdb
│      │  ConsoleApp1.runtimeconfig.json
│      │  coreclr.dll
│      │  createdump.exe
│      │  dbgshim.dll
│      │  hostfxr.dll
│      │  hostpolicy.dll
│      │  Microsoft.CSharp.dll
│      │  Microsoft.DiaSymReader.Native.amd64.dll
│      │  Microsoft.Toolkit.Uwp.Notifications.dll
│      │  Microsoft.VisualBasic.Core.dll
│      │  Microsoft.VisualBasic.dll
│      │  Microsoft.Win32.Primitives.dll
│      │  Microsoft.Win32.Registry.dll
│      │  Microsoft.Win32.SystemEvents.dll
│      │  Microsoft.Windows.SDK.NET.dll
│      │  mscordaccore.dll
│      │  mscordaccore_amd64_amd64_6.0.21.52210.dll
│      │  mscordbi.dll
│      │  mscorlib.dll
│      │  mscorrc.dll
│      │  msquic.dll
│      │  netstandard.dll
│      │  System.AppContext.dll
│      │  System.Buffers.dll
│      │  System.Collections.Concurrent.dll
│      │  System.Collections.dll
│      │  System.Collections.Immutable.dll
│      │  System.Collections.NonGeneric.dll
│      │  System.Collections.Specialized.dll
│      │  System.ComponentModel.Annotations.dll
│      │  System.ComponentModel.DataAnnotations.dll
│      │  System.ComponentModel.dll
│      │  System.ComponentModel.EventBasedAsync.dll
│      │  System.ComponentModel.Primitives.dll
│      │  System.ComponentModel.TypeConverter.dll
│      │  System.Configuration.dll
│      │  System.Console.dll
│      │  System.Core.dll
│      │  System.Data.Common.dll
│      │  System.Data.DataSetExtensions.dll
│      │  System.Data.dll
│      │  System.Diagnostics.Contracts.dll
│      │  System.Diagnostics.Debug.dll
│      │  System.Diagnostics.DiagnosticSource.dll
│      │  System.Diagnostics.FileVersionInfo.dll
│      │  System.Diagnostics.Process.dll
│      │  System.Diagnostics.StackTrace.dll
│      │  System.Diagnostics.TextWriterTraceListener.dll
│      │  System.Diagnostics.Tools.dll
│      │  System.Diagnostics.TraceSource.dll
│      │  System.Diagnostics.Tracing.dll
│      │  System.dll
│      │  System.Drawing.Common.dll
│      │  System.Drawing.dll
│      │  System.Drawing.Primitives.dll
│      │  System.Dynamic.Runtime.dll
│      │  System.Formats.Asn1.dll
│      │  System.Globalization.Calendars.dll
│      │  System.Globalization.dll
│      │  System.Globalization.Extensions.dll
│      │  System.IO.Compression.Brotli.dll
│      │  System.IO.Compression.dll
│      │  System.IO.Compression.FileSystem.dll
│      │  System.IO.Compression.Native.dll
│      │  System.IO.Compression.ZipFile.dll
│      │  System.IO.dll
│      │  System.IO.FileSystem.AccessControl.dll
│      │  System.IO.FileSystem.dll
│      │  System.IO.FileSystem.DriveInfo.dll
│      │  System.IO.FileSystem.Primitives.dll
│      │  System.IO.FileSystem.Watcher.dll
│      │  System.IO.IsolatedStorage.dll
│      │  System.IO.MemoryMappedFiles.dll
│      │  System.IO.Pipes.AccessControl.dll
│      │  System.IO.Pipes.dll
│      │  System.IO.UnmanagedMemoryStream.dll
│      │  System.Linq.dll
│      │  System.Linq.Expressions.dll
│      │  System.Linq.Parallel.dll
│      │  System.Linq.Queryable.dll
│      │  System.Memory.dll
│      │  System.Net.dll
│      │  System.Net.Http.dll
│      │  System.Net.Http.Json.dll
│      │  System.Net.HttpListener.dll
│      │  System.Net.Mail.dll
│      │  System.Net.NameResolution.dll
│      │  System.Net.NetworkInformation.dll
│      │  System.Net.Ping.dll
│      │  System.Net.Primitives.dll
│      │  System.Net.Quic.dll
│      │  System.Net.Requests.dll
│      │  System.Net.Security.dll
│      │  System.Net.ServicePoint.dll
│      │  System.Net.Sockets.dll
│      │  System.Net.WebClient.dll
│      │  System.Net.WebHeaderCollection.dll
│      │  System.Net.WebProxy.dll
│      │  System.Net.WebSockets.Client.dll
│      │  System.Net.WebSockets.dll
│      │  System.Numerics.dll
│      │  System.Numerics.Vectors.dll
│      │  System.ObjectModel.dll
│      │  System.Private.CoreLib.dll
│      │  System.Private.DataContractSerialization.dll
│      │  System.Private.Uri.dll
│      │  System.Private.Xml.dll
│      │  System.Private.Xml.Linq.dll
│      │  System.Reflection.DispatchProxy.dll
│      │  System.Reflection.dll
│      │  System.Reflection.Emit.dll
│      │  System.Reflection.Emit.ILGeneration.dll
│      │  System.Reflection.Emit.Lightweight.dll
│      │  System.Reflection.Extensions.dll
│      │  System.Reflection.Metadata.dll
│      │  System.Reflection.Primitives.dll
│      │  System.Reflection.TypeExtensions.dll
│      │  System.Resources.Reader.dll
│      │  System.Resources.ResourceManager.dll
│      │  System.Resources.Writer.dll
│      │  System.Runtime.CompilerServices.Unsafe.dll
│      │  System.Runtime.CompilerServices.VisualC.dll
│      │  System.Runtime.dll
│      │  System.Runtime.Extensions.dll
│      │  System.Runtime.Handles.dll
│      │  System.Runtime.InteropServices.dll
│      │  System.Runtime.InteropServices.RuntimeInformation.dll
│      │  System.Runtime.Intrinsics.dll
│      │  System.Runtime.Loader.dll
│      │  System.Runtime.Numerics.dll
│      │  System.Runtime.Serialization.dll
│      │  System.Runtime.Serialization.Formatters.dll
│      │  System.Runtime.Serialization.Json.dll
│      │  System.Runtime.Serialization.Primitives.dll
│      │  System.Runtime.Serialization.Xml.dll
│      │  System.Security.AccessControl.dll
│      │  System.Security.Claims.dll
│      │  System.Security.Cryptography.Algorithms.dll
│      │  System.Security.Cryptography.Cng.dll
│      │  System.Security.Cryptography.Csp.dll
│      │  System.Security.Cryptography.Encoding.dll
│      │  System.Security.Cryptography.OpenSsl.dll
│      │  System.Security.Cryptography.Primitives.dll
│      │  System.Security.Cryptography.X509Certificates.dll
│      │  System.Security.dll
│      │  System.Security.Principal.dll
│      │  System.Security.Principal.Windows.dll
│      │  System.Security.SecureString.dll
│      │  System.ServiceModel.Web.dll
│      │  System.ServiceProcess.dll
│      │  System.Text.Encoding.CodePages.dll
│      │  System.Text.Encoding.dll
│      │  System.Text.Encoding.Extensions.dll
│      │  System.Text.Encodings.Web.dll
│      │  System.Text.Json.dll
│      │  System.Text.RegularExpressions.dll
│      │  System.Threading.Channels.dll
│      │  System.Threading.dll
│      │  System.Threading.Overlapped.dll
│      │  System.Threading.Tasks.Dataflow.dll
│      │  System.Threading.Tasks.dll
│      │  System.Threading.Tasks.Extensions.dll
│      │  System.Threading.Tasks.Parallel.dll
│      │  System.Threading.Thread.dll
│      │  System.Threading.ThreadPool.dll
│      │  System.Threading.Timer.dll
│      │  System.Transactions.dll
│      │  System.Transactions.Local.dll
│      │  System.ValueTuple.dll
│      │  System.Web.dll
│      │  System.Web.HttpUtility.dll
│      │  System.Windows.dll
│      │  System.Xml.dll
│      │  System.Xml.Linq.dll
│      │  System.Xml.ReaderWriter.dll
│      │  System.Xml.Serialization.dll
│      │  System.Xml.XDocument.dll
│      │  System.Xml.XmlDocument.dll
│      │  System.Xml.XmlSerializer.dll
│      │  System.Xml.XPath.dll
│      │  System.Xml.XPath.XDocument.dll
│      │  ucrtbase.dll
│      │  UnitTestJikken.dll
│      │  UnitTestJikken.pdb
│      │  WindowsBase.dll
│      │  WinRT.Runtime.dll
│      │  
│      └─ref
│              ConsoleApp1.dll

RuntimeIdentifierは指定せず、SelfContainedだけ指定

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework>
    <Platforms>x64</Platforms>
      <SelfContained>true</SelfContained>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\UnitTestJikken\UnitTestJikken.csproj" />
  </ItemGroup>
</Project>

SelfContainedはRuntimeIdentifierを指定していないと設定できない。(エラーになる)
どの環境(Windows?Linux?)がわからないと、なんのランタイムを含めて良いかがわからない、ということか。

f:id:tera1707:20220209220849p:plain

ProduceReferenceAssembly をfalseにする

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework>
    <Platforms>x64</Platforms>
      <ProduceReferenceAssembly>false</ProduceReferenceAssembly>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\UnitTestJikken\UnitTestJikken.csproj" />
  </ItemGroup>
</Project>

ProduceReferenceAssembly falseにすると、falseにしてないとき(標準の時)に出力先にできていた、refフォルダができなくなる。

└─net6.0-windows10.0.17763.0
    │  ConsoleApp1.deps.json
    │  ConsoleApp1.dll
    │  ConsoleApp1.exe
    │  ConsoleApp1.pdb
    │  ConsoleApp1.runtimeconfig.json
    │  Microsoft.Toolkit.Uwp.Notifications.dll
    │  Microsoft.Win32.SystemEvents.dll
    │  Microsoft.Windows.SDK.NET.dll
    │  System.Drawing.Common.dll
    │  UnitTestJikken.dll
    │  UnitTestJikken.pdb
    │  WinRT.Runtime.dll
    │  
    └─runtimes
        ├─unix
        │  └─lib
        │      └─netcoreapp3.0
        │              System.Drawing.Common.dll
        │              
        └─win
            └─lib
                └─netcoreapp3.0
                        Microsoft.Win32.SystemEvents.dll
                        System.Drawing.Common.dll

refフォルダに入っているのは、参照アセンブリというものらしい。 そういうものがあると知らなかったが、簡単に言うと「publicなクラスやメソッドのインターフェースだけあって中身の実装のない、そのアセンブリを使う側が実装に使えるもの」らしい。

詳しくはMS公式を参照。

MSBuildに使うProduceReferenceAssemblyオプション
C# コンパイラ オプション - 出力オプション | Microsoft Docs

参照アセンブリとは何か?
docs.microsoft.com

dotnet publish をやってみる

コマンドプロンプトでソリューションファイルと同じ階層にcdして、下記コマンドをうつ。

dotnet publish --no-self-contained

そのとき、csprojファイルは、下記のような内容にしていた。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework>
    <Platforms>x64</Platforms>
     <SelfContained>true</SelfContained>
     <RuntimeIdentifier>win-x64</RuntimeIdentifier>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\UnitTestJikken\UnitTestJikken.csproj" />
  </ItemGroup>
</Project>

そうすると、下記のようなものが出力される。

└─net6.0-windows10.0.17763.0
    └─win-x64
        │  ConsoleApp1.deps.json
        │  ConsoleApp1.dll
        │  ConsoleApp1.exe
        │  ConsoleApp1.pdb
        │  ConsoleApp1.runtimeconfig.json
        │  Microsoft.Toolkit.Uwp.Notifications.dll
        │  Microsoft.Win32.SystemEvents.dll
        │  Microsoft.Windows.SDK.NET.dll
        │  System.Drawing.Common.dll
        │  UnitTestJikken.dll
        │  UnitTestJikken.pdb
        │  WinRT.Runtime.dll
        │  
        ├─publish
        │      ConsoleApp1.deps.json
        │      ConsoleApp1.dll
        │      ConsoleApp1.exe
        │      ConsoleApp1.pdb
        │      ConsoleApp1.runtimeconfig.json
        │      Microsoft.Toolkit.Uwp.Notifications.dll
        │      Microsoft.Win32.SystemEvents.dll
        │      Microsoft.Windows.SDK.NET.dll
        │      System.Drawing.Common.dll
        │      UnitTestJikken.dll
        │      UnitTestJikken.pdb
        │      WinRT.Runtime.dll
        │      
        └─ref
                ConsoleApp1.dll

csprojでは、<SelfContained>true</SelfContained>にして、dotnetコマンドでは--no-self-containedにした。 その結果、self-contained(自己完結)がfalseの成果物が作成された。

→csprojの設定は、dotnet publishしたときのオプション設定で上書きされるっぽい。
 (すべての設定がそうなるかどうかは不明)

dotnet publish で --outputで出力先フォルダを指定する

dotnet publish でoutputフォルダを指定しなかった場合、csprojの標準の出力先フォルダに「publish」フォルダができて、そこにpublishの出力が行われるっぽい。

こちら f:id:tera1707:20220212231311p:plain

--output を使って、dotnet publish の出力先を指定できる模様。
下記のコマンドを実行した。(csprojの設定は、上のと同じ)

dotnet publish --no-self-contained --output C:\Users\masa\Desktop\jikken

結果、デスクトップのjikkenフォルダに、下記のような出力がされる。

│  ConsoleApp1.deps.json
│  ConsoleApp1.dll
│  ConsoleApp1.exe
│  ConsoleApp1.pdb
│  ConsoleApp1.runtimeconfig.json
│  Microsoft.Toolkit.Uwp.Notifications.dll
│  Microsoft.Win32.SystemEvents.dll
│  Microsoft.Windows.SDK.NET.dll
│  System.Drawing.Common.dll
│  UnitTestJikken.deps.json
│  UnitTestJikken.dll
│  UnitTestJikken.pdb
│  WinRT.Runtime.dll
│  
└─runtimes
    ├─unix
    │  └─lib
    │      └─netcoreapp3.0
    │              System.Drawing.Common.dll
    │              
    └─win
        └─lib
            └─netcoreapp3.0
                    Microsoft.Win32.SystemEvents.dll
                    System.Drawing.Common.dll

csprojの出力先にも、下記のようなものが出来上がっている。

└─net6.0-windows10.0.17763.0
    └─win-x64
        │  ConsoleApp1.deps.json
        │  ConsoleApp1.dll
        │  ConsoleApp1.exe
        │  ConsoleApp1.pdb
        │  ConsoleApp1.runtimeconfig.json
        │  Microsoft.Toolkit.Uwp.Notifications.dll
        │  Microsoft.Win32.SystemEvents.dll
        │  Microsoft.Windows.SDK.NET.dll
        │  System.Drawing.Common.dll
        │  UnitTestJikken.dll
        │  UnitTestJikken.pdb
        │  WinRT.Runtime.dll
        │  
        └─ref
                ConsoleApp1.dll

2つのフォルダの中の、同じファイル名のものは同じバイナリになってる。 ただ、csprojの出力先のほうにはruntimesフォルダがないが、dotnet publishの出力先フォルダのほうにはある。

→おそらく、csprojの方ではRuntimeIdentifierフォルダにwin-x64を指定していたのでruntimesフォルダはできなかったが、dotnet publishのほうではRuntimeIDを指定しなかったので、runtimesフォルダができたのだと思われる。

⇒csprojとdotnet publishで同じ設定をしたらdotnetの方が優先だが、csprojの方にだけ設定してると、dotnet publishのほうでは、設定しなかった場合のデフォルト値が使われるっぽい。

VSでビルドしたときとdotnet puslishしたときで出来るバイナリは異なるのか?

異ならない。同じバイナリができてる。

f:id:tera1707:20220212233141p:plain

左:VisualStdio2022でDebugビルドしたもの。
  (<SelfContained>false</SelfContained>だけ指定) 右:dotnet publish --no-self-containedを実行したもの。

結局、最終成果物として使うのはどの方法でビルドしたものを使うべきなのか?

試した結果、個々のファイルは同じものができてるので、究極どちらを使ってもよさそう。(同じ設定をしたときには、違いはrefフォルダができるかできないかくらいっぽい。)

今一度MS公式を見ると、
dotnet-publishコマンドのMS公式説明に、下記のようなものがある。

f:id:tera1707:20220212225429p:plain

アプリの正式な展開方法はこれだけ、という記述があるので、VisualStudioでリリースビルドしたフォルダの中身を使うよりも、dotnet publishで出力したものを使うべきなのだと思われる。

その際、(csprojファイルにどんな設定をしていても)、dotnet publishコマンドに、作ったコードの対象となる環境に適したすべてのオプションを設定してやれば、そこで動くものが出来上がるよ、ということか。

思ったこと

dotnet publishを使えばよい、で納得した気がするが、
たぶんコードを書いている最中はVisualStudioでビルドするのでcsprojの設定が生きてるが、最後、最終版を作ってテストするときにはdotnet publishとかになりそうな気がする。

そうなると、最後の最後でcsprojとdotnet publishに渡すオプションが違ってしまい、今までOKだったのに最終テストではなんか違う動きする、ということがあり得そう。

そこは要注意だなと感じた。

備考

dotnet publishでは、VSからビルドしたときにできていたrefフォルダが作成されない。
たぶん、refはその中にあるdllを、そのdllを使う側がライブラリとして使用するためのものなので、「publish = 動かす環境に配置」するときには、そんな参照アセンブリは不要、ということで出来ないのだと思われる。

参考

.NET SDK プロジェクトの MSBuild リファレンス docs.microsoft.com

MSBuild コマンド ライン リファレンス docs.microsoft.com

単一ファイルの発行関連パラメータの説明 単一ファイル アプリケーション - .NET | Microsoft Docs

dotnetコマンド
docs.microsoft.com

dotnet-publishコマンド docs.microsoft.com

"win-x64"などの表記を「RID(ランタイムID)」という
docs.microsoft.com

refフォルダがなにか? docs.microsoft.com

www.fixes.pub