C#でカレントディレクトリを取得する

# 目的

- C#でアプリケーションのカレントディレクトリを取得するメソッドの挙動検証

# 取得方法いろいろ

### System.AppDomain.CurrentDomain.BaseDirectory

- ref
  - https://docs.microsoft.com/ja-jp/dotnet/api/system.appdomain.basedirectory?view=netcore-3.1
- アセンブリを探すためにアセンブリ リゾルバーが使用したベース ディレクトリを取得

### Directory.GetCurrentDirectory()

- ref
  - https://docs.microsoft.com/ja-jp/dotnet/api/system.io.directory.getcurrentdirectory?view=netcore-3.1
- アプリケーションの現在の作業ディレクトリを取得

### Directory.GetParent(Assembly.GetExecutingAssembly().Location)

- ref
  - https://docs.microsoft.com/ja-jp/dotnet/api/system.reflection.assembly.getexecutingassembly?view=netcore-3.1
  - https://docs.microsoft.com/ja-jp/dotnet/api/system.reflection.assembly.location?view=netcore-3.1#System_Reflection_Assembly_Location
- 現在実行中のコードを格納しているアセンブリの、マニフェストを格納している読み込み済みファイルの完全パスまたは UNC 位置の親ディレクトリを取得

### Environment.CurrentDirectory

- ref
  - https://docs.microsoft.com/ja-jp/dotnet/api/system.environment.currentdirectory?view=netcore-3.1
- 現在の作業ディレクトリの完全修飾パスを取得

### System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(Environment.GetCommandLineArgs()[0]))

- ref
  - https://docs.microsoft.com/ja-jp/dotnet/api/system.environment.getcommandlineargs?view=netcore-3.1
- 現在のプロセスに対するコマンド ライン引数を格納している文字列配列の先頭（ファイルパス）のディレクトリ情報

### System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName)

- ref
  - https://docs.microsoft.com/ja-jp/dotnet/api/system.diagnostics.process.getcurrentprocess?view=netcore-3.1
  - https://docs.microsoft.com/ja-jp/dotnet/api/system.diagnostics.process.mainmodule?view=netcore-3.1#System_Diagnostics_Process_MainModule
  - https://docs.microsoft.com/ja-jp/dotnet/api/system.diagnostics.processmodule.filename?view=netcore-3.1#System_Diagnostics_ProcessModule_FileName
- 現在アクティブなプロセスのメイン モジュールの完全なパスのディレクトリ情報

# 検証

検証用のソースコード

```bash
pwd
  # /home/ec2-user/dotnet-app
ls -l
  # total 8
  # -rw-rw-r-- 1 ec2-user ec2-user 225 Aug 15 03:47 dotnet-app.csproj
  # -rw-rw-r-- 1 ec2-user ec2-user 751 Aug 15 04:03 Program.cs
```

```Program.cs
using System;
using System.IO;
using System.Reflection;

namespace dotnet_app
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(System.AppDomain.CurrentDomain.BaseDirectory);
            Console.WriteLine(Directory.GetCurrentDirectory());
            Console.WriteLine(Directory.GetParent(Assembly.GetExecutingAssembly().Location));
            Console.WriteLine(Environment.CurrentDirectory);
            Console.WriteLine(System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(Environment.GetCommandLineArgs()[0])));
            Console.WriteLine(System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName));
        }
    }
}
```

プロジェクトファイル（`.csproj`）のあるディレクトリで `dotnet run` を実行

```bash
pwd
  # /home/ec2-user/dotnet-app
dotnet run
  # /home/ec2-user/dotnet-app/bin/Debug/netcoreapp3.1/
  # /home/ec2-user/dotnet-app
  # /home/ec2-user/dotnet-app/bin/Debug/netcoreapp3.1
  # /home/ec2-user/dotnet-app
  # /home/ec2-user/dotnet-app/bin/Debug/netcoreapp3.1
  # /home/ec2-user/dotnet-app/bin/Debug/netcoreapp3.1
```

プロジェクトファイル（`.csproj`）のあるディレクトリ以外で `dotnet run` を実行

```bash
pwd
  # /home/ec2-user
dotnet run --project dotnet-app/dotnet-app.csproj
  # /home/ec2-user/dotnet-app/bin/Debug/netcoreapp3.1/
  # /home/ec2-user
  # /home/ec2-user/dotnet-app/bin/Debug/netcoreapp3.1
  # /home/ec2-user
  # /home/ec2-user/dotnet-app/bin/Debug/netcoreapp3.1
  # /home/ec2-user/dotnet-app/bin/Debug/netcoreapp3.1
```

---

実行ファイルを作成

```bash
pwd
  # /home/ec2-user/dotnet-app
dotnet publish -c Release -r linux-x64 -p:PublishSingleFile=true
  # Microsoft (R) Build Engine version 16.7.0-preview-20360-03+188921e2f for .NET
  # Copyright (C) Microsoft Corporation. All rights reserved.
  # 
  #   Determining projects to restore...
  #   Restored /home/ec2-user/dotnet-app/dotnet-app.csproj (in 340 ms).
  #   dotnet-app -> /home/ec2-user/dotnet-app/bin/Release/netcoreapp3.1/linux-x64/dotnet-app.dll
  #   dotnet-app -> /home/ec2-user/dotnet-app/bin/Release/netcoreapp3.1/linux-x64/publish/
```

---

（実行ファイルのあるディレクトリで）実行ファイルを起動

```bash
pwd
  # /home/ec2-user/dotnet-app/bin/Release/netcoreapp3.1/linux-x64/publish
./dotnet-app
  # /var/tmp/.net/ec2-user/dotnet-app/pbhxfno5.xnt/
  # /home/ec2-user/dotnet-app/bin/Release/netcoreapp3.1/linux-x64/publish
  # /var/tmp/.net/ec2-user/dotnet-app/pbhxfno5.xnt
  # /home/ec2-user/dotnet-app/bin/Release/netcoreapp3.1/linux-x64/publish
  # /var/tmp/.net/ec2-user/dotnet-app/pbhxfno5.xnt
  # /home/ec2-user/dotnet-app/bin/Release/netcoreapp3.1/linux-x64/publish
```

実行ファイルを起動

```bash
pwd
  # /home/ec2-user/dotnet-app
./bin/Release/netcoreapp3.1/linux-x64/publish/dotnet-app
  # /var/tmp/.net/ec2-user/dotnet-app/pbhxfno5.xnt/
  # /home/ec2-user/dotnet-app
  # /var/tmp/.net/ec2-user/dotnet-app/pbhxfno5.xnt
  # /home/ec2-user/dotnet-app
  # /var/tmp/.net/ec2-user/dotnet-app/pbhxfno5.xnt
  # /home/ec2-user/dotnet-app/bin/Release/netcoreapp3.1/linux-x64/publish
```

# 考察

以下のような要件があった場合

- 実行ファイルと同じディレクトリにファイルを出力させるプログラムを作成。
- また、このプログラムは、他のアプリケーションから呼ばれることを想定している。

`System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName))` がいいのかな。