rksoftware

Visual Studio とか C# とかが好きです

.NET Core 3.0 単一ファイルの実行可能ファイルの実行時のアセンブリ

.NET Core 3.0 の新機能で 単一ファイルの実行可能ファイル というものがあります。PublishSingleFile という方がなじむ方もいるかもしれません。

■ PublishSingleFile

簡単に言うと、 .dll なんかを一つの .exe ファイルに固めて発行する機能です。配布時にファイル一つだけをコピーするだけで配置できます。私も期待しています。

■ アセンブリの扱いは変わってしまうの?

そこで気になるのが、これまで複数アセンブリ (.dll) で構成されることを前提に書いていたコードはどうなるのか? ですよね。
結論から言うとあまり変わりません。ただし、Assembly.Location と CurrentDirectory は気にする必要はあります。

次の記事はプレビューの頃に PublishSingleFile の実行時にどうなるか試した記事です。

簡単にまとめると、実行時にアセンブリ (.dll) が Temp に展開されて、展開されたアセンブリが使われます。

■ 改めて試してみる (結論)

リリース版で改めて試してみます。まずは結論から。

次のコードで、実行時にどうなっているか確認してみます。プロジェクトは C:\TestProject に作ったものとしています。

using System;

namespace TestProject
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"CurrentDirectory       : {Environment.CurrentDirectory}");
            Console.WriteLine($"CommandLine            : {Environment.CommandLine}");
            Console.WriteLine($"EntryAssembly.FullName : {System.Reflection.Assembly.GetEntryAssembly().FullName}");
            Console.WriteLine($"Assembly.FullName      : {typeof(Program).Assembly.FullName}");
            Console.WriteLine($"EntryAssembly.Location : {System.Reflection.Assembly.GetEntryAssembly().Location}");
            Console.WriteLine($"Assembly.Location      : {typeof(Program).Assembly.Location}");

            Console.ReadKey();
        }
    }
}

実行結果

CurrentDirectory       : C:\TestProject
CommandLine            : C:\Users\{ユーザ名}\AppData\Local\Temp\.net\TestProject\{ランダムな文字列}\TestProject.dll
EntryAssembly.FullName : TestProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Assembly.FullName      : TestProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
EntryAssembly.Location : C:\Users\{ユーザ名}\AppData\Local\Temp\.net\TestProject\{ランダムな文字列}\TestProject.dll
Assembly.Location      : C:\Users\{ユーザ名}\AppData\Local\Temp\.net\TestProject\{ランダムな文字列}\TestProject.dll

アセンブリが Temp に展開されてい使われているのが分かります。

■ 確認手順

今回、基本はコマンドラインで操作します。IDE を使ってもいいのですが、コマンドの方が書きやすいので。

プロジェクトの新規作成

console がコンソールアプリプ色ジェクトを作ることを指定しています。

> dotnet new console --name TestProject

コードを書く

using System;

namespace TestProject
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"CurrentDirectory       : {Environment.CurrentDirectory}");
            Console.WriteLine($"CommandLine            : {Environment.CommandLine}");
            Console.WriteLine($"EntryAssembly.FullName : {System.Reflection.Assembly.GetEntryAssembly().FullName}");
            Console.WriteLine($"Assembly.FullName      : {typeof(Program).Assembly.FullName}");
            Console.WriteLine($"EntryAssembly.Location : {System.Reflection.Assembly.GetEntryAssembly().Location}");
            Console.WriteLine($"Assembly.Location      : {typeof(Program).Assembly.Location}");

            Console.ReadKey();
        }
    }
}

発行する

> dotnet publish -c Release -r win10-x64 /p:PublishSingleFile=true

実行する

> bin\Release\netcoreapp3.0\win10-x64\publish\TestProject.exe

実行結果は前述のとおりです。

各フォルダのファイルを確認

(.pdb) ファイルを含む)

フォルダ ファイル数 サイズ(合計)
1 単一ファイルの発行 .exe と .pdb の 2 ファイル 69,017,600 バイト
2 単一ファイルでない発行 225 個のファイル 69,427,200 バイト
3 Temp のファイル 223 個のファイル 69,255,168 バイト

2 と 3 の違いは次の 2 ファイルです。

  • TestProject.exe
  • TestProject.pdb

■ 注意点

発行しなおすたびに {ランダムな文字列} が変わってどんどん Temp にフォルダとアセンブリが増え続けます。古いバージョンを消してくれたりはしません。Temp なので構わないと言えば構わないのですが。
油断しているとディスク使用量が増えていてちょっとびっくりしたりします。