はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【C#】EmbeddedResource vs CopyToPublishDirectoryとCopyToOutputDirectory、どちらを選ぶべきか

はじめに

アプリケーションを開発している際に何かの設定ファイルや画像などのリソースも一緒に配布したいときがあると思います。.NETでは以下のような組み込み方法があります。

  • EmbeddedResource
  • CopyToPublishDirectoryCopyToOutputDirectory

それぞれについて解説した後、簡単な比較を行いたいと思います。

概要

EmbeddedResource

EmbeddedResourceはアセンブリ(.dll.exe)の中に直接ファイルを組み込む手法です。

<!-- csprojに下記を記載してリソースを組み込む -->
<ItemGroup>
    <EmbeddedResource Include="./sample.txt" LogicalName="sample.txt" />
</ItemGroup>
// Program.cs
using System.Reflection;

var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream("sample.txt");
if (stream == null)
{
    throw new FileNotFoundException("Resource not found: sample.txt");
}
using var streamReader = new StreamReader(stream);
var content = streamReader.ReadToEnd();
Console.WriteLine(content);

EmbeddedResourceには以下のメリットがあります。

  • アセンブリに組み込まれるため配布が楽
  • ユーザーによる編集がしにくい

逆にデメリットは以下でしょうか。

  • アセンブリサイズの肥大化
  • コンパイル時以外に編集不可
  • アクセス方法が特殊

CopyToPublishDirectory & CopyToOutputDirectory

CopyToPublishDirectoryCopyToOutputDirectoryはビルド時またはパブリッシュ時に、指定されたファイルを実行ファイルと同じディレクトリ(またはサブディレクトリ)にコピーする方法です。

  • CopyToOutputDirectory : dotnet build実行時
  • CopyToPublishDirectory : dotnet publish実行時

CopyToOutputDirectoryを定義した場合は、bin\Debug\net8.0\bin\Release\net8.0\といったパスにもファイルが吐き出されます。逆にCopyToPublishDirectoryのみ定義している場合はdotnet runを実行しても吐き出されません。

<!-- csprojに下記を記載してリソースを組み込む -->
<ItemGroup>
    <Content Include="./sample.txt" >
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
    </Content>
</ItemGroup>
// Program.cs
var path = Path.Combine(AppContext.BaseDirectory, "sample.txt");
if (File.Exists(path))
{
    Console.WriteLine("File exists.");
}
else
{
    Console.WriteLine("File does not exist.");
}

メリットは以下あたりでしょうか。

  • アセンブリのファイルサイズを抑えることができる
  • コンパイル後にも中身を編集ができる
  • アクセス手法が簡単

逆にデメリットもあります。

  • デプロイが比較的複雑になる
  • ファイルの消失・改ざんのリスク
  • パスの管理が必要

どちらを利用すべきか

以下が重要な観点になると思います。

  • ユーザーがファイルを編集しても良いかどうか
  • ファイルの変更が頻繁にあるかどうか

EmbeddedResourceはファイルがアセンブリに組み込まれるので編集は基本的にできません。しかしユーザーに編集をしてもらいたい場合には困るでしょう。開発者が中身を編集したい場合には、再度コンパイルしてユーザーへと配布する必要がでてきますが、CopyToPublishDirectoryCopyToOutputDirectoryはアセンブリに変更がなければコンパイルの必要はありません。

また一応ユーザーに見られては困るファイルはEmbeddedResourceにしておいた方が比較的知られずらいですが、中身をみようと思ったら割と簡単に見れるのでまあ気休め程度だとは思っておいた方が無難です。