C#を用いたアプリケーション開発において、動作している環境のランタイムバージョンや実行プログラム自身のアセンブリバージョンを正確に取得することは、デバッグ、ログ出力、あるいは互換性の維持において極めて重要です。

特に現代の.NET(旧.NET Core以降のモダンな.NET)では、複数のバージョンが共存しやすく、意図したランタイムで動作しているかを確認するコードの実装は欠かせません。

本記事では、C#を使用して「.NETランタイムのバージョン」「実行中のアセンブリのバージョン」「OSなどの環境情報」を取得する方法について、初心者から中級者までが実戦で活用できるよう、詳細なコード例とともに解説します。

.NETランタイムのバージョンを取得する方法

アプリケーションが現在どの.NETランタイム上で動作しているかを知ることは、特定のフレームワーク機能に依存した処理を行う際の判断基準となります。

C#では、主に2つのアプローチでこれを取得できます。

Environment.Versionによる取得

System.Environment.Versionプロパティを使用すると、現在のプロセスを実行している共通言語ランタイム(CLR)のバージョンを取得できます。

C#
using System;

class Program
{
    static void Main()
    {
        // Environment.Versionを使用してCLRのバージョンを取得
        Version clrVersion = Environment.Version;

        Console.WriteLine("--- Environment.Version による出力 ---");
        Console.WriteLine($"Full Version: {clrVersion}");
        Console.WriteLine($"Major: {clrVersion.Major}");
        Console.WriteLine($"Minor: {clrVersion.Minor}");
        Console.WriteLine($"Build: {clrVersion.Build}");
        Console.WriteLine($"Revision: {clrVersion.Revision}");
    }
}

実行結果の例(.NET 8環境の場合):

実行結果
--- Environment.Version による出力 ---
Full Version: 8.0.0
Major: 8
Minor: 0
Build: 0
Revision: -1

ただし、注意点として、このプロパティが返すのは「CLR(共通言語ランタイム)」のバージョンです。

.NET Framework時代はフレームワークのバージョンとCLRのバージョンが必ずしも一致しない(例:.NET Framework 4.5から4.8まではCLR 4.0を使用)という現象がありましたが、モダンな.NET(5以降)では製品バージョンに近い値が返されるようになっています。

RuntimeInformationによる詳細な名称取得

より人間が読みやすい形式、あるいは「.NET 8.0.1」といったパッチバージョンを含む正確な製品名を取得したい場合は、System.Runtime.InteropServices.RuntimeInformationクラスを使用します。

C#
using System;
using System.Runtime.InteropServices;

class Program
{
    static void Main()
    {
        // 実行中の.NETの名称とバージョンを取得
        string frameworkDescription = RuntimeInformation.FrameworkDescription;

        Console.WriteLine("--- RuntimeInformation による出力 ---");
        Console.WriteLine($"Description: {frameworkDescription}");
    }
}
実行結果
--- RuntimeInformation による出力 ---
Description: .NET 8.0.1

このメソッドは、「.NET」という名称も含めた文字列を返すため、ログファイルへの出力や、診断画面の表示に最適です。

アセンブリのバージョンを取得する方法

「作成したアプリケーション自体のバージョン」を取得する方法はいくつかあり、それぞれ取得できる情報の種類が異なります。

C#プロジェクトには主に3つのバージョン属性が存在します。

  1. AssemblyVersion:.NETのランタイムがアセンブリの識別(バインディング)に使用するバージョン。
  2. AssemblyFileVersion:Windowsのエクスプローラーなどでファイルプロパティとして表示されるバージョン。
  3. AssemblyInformationalVersion:製品バージョンとして定義される文字列。セマンティックバージョニング(例:1.0.0-beta)なども含めることが可能。

実行中のアセンブリから取得する

現在実行されているメソッドが含まれるアセンブリ(通常は自身のプログラム)のバージョンを取得するには、System.Reflection.Assemblyクラスを使用します。

C#
using System;
using System.Reflection;

class Program
{
    static void Main()
    {
        // 実行中のアセンブリ情報を取得
        Assembly assembly = Assembly.GetExecutingAssembly();
        
        // AssemblyNameオブジェクトからバージョンを取得
        Version version = assembly.GetName().Version;

        Console.WriteLine("--- アセンブリバージョンの取得 ---");
        Console.WriteLine($"Assembly Name: {assembly.GetName().Name}");
        Console.WriteLine($"Version: {version}");
    }
}
実行結果
--- アセンブリバージョンの取得 ---
Assembly Name: MyApp
Version: 1.0.0.0

エントリアセンブリ(起動元)から取得する

ライブラリ(DLL)側から、そのライブラリを呼び出しているメインの実行ファイル(EXE)のバージョンを知りたい場合は、GetEntryAssembly()を使用します。

C#
Assembly entryAssembly = Assembly.GetEntryAssembly();
if (entryAssembly != null)
{
    Console.WriteLine($"Entry Assembly Version: {entryAssembly.GetName().Version}");
}

注意: 単体テスト実行時や、アンマネージドコードから呼び出された場合、GetEntryAssembly()nullを返す可能性があるため、必ずヌルチェックを行ってください。

FileVersionInfoによる詳細な属性取得

アセンブリのメタデータに記録されている「ファイルバージョン」や「製品バージョン」を取得するには、System.Diagnostics.FileVersionInfoクラスが便利です。

これはエクスプローラーの「詳細」タブに表示される情報と一致します。

C#
using System;
using System.Diagnostics;
using System.Reflection;

class Program
{
    static void Main()
    {
        // 実行ファイルのパスを取得
        string location = Assembly.GetExecutingAssembly().Location;
        
        // パスが空(Single File起動など)の場合はプロセスのメインモジュールから取得
        if (string.IsNullOrEmpty(location))
        {
            location = Process.GetCurrentProcess().MainModule.FileName;
        }

        // ファイルバージョン情報を取得
        FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(location);

        Console.WriteLine("--- FileVersionInfo による詳細情報 ---");
        Console.WriteLine($"ファイルバージョン: {fvi.FileVersion}");
        Console.WriteLine($"製品バージョン: {fvi.ProductVersion}");
        Console.WriteLine($"会社名: {fvi.CompanyName}");
        Console.WriteLine($"製品名: {fvi.ProductName}");
        Console.WriteLine($"著作権: {fvi.LegalCopyright}");
    }
}
実行結果
--- FileVersionInfo による詳細情報 ---
ファイルバージョン: 1.0.0.0
製品バージョン: 1.0.0-alpha+commit12345
会社名: MyCompany Corp.
製品名: MyGreatApp
著作権: Copyright (C) 2024

FileVersionInfoを使用するメリットは、アセンブリロードを行わずにファイルパスから直接情報を読み取れる点、および文字列ベースの「製品バージョン(Informational Version)」を取得できる点にあります。

プロジェクトファイル(.csproj)でのバージョン定義

モダンなC#開発では、AssemblyInfo.csを直接編集するのではなく、.csprojファイル内にバージョン情報を記述するのが一般的です。

以下の表は、プロジェクトファイル内のタグと、C#コードで取得される値の対応関係をまとめたものです。

.csproj内のタグC#での取得方法(プロパティ)役割
<Version>fvi.ProductVersion製品全体のバージョン(デフォルト)
<AssemblyVersion>assembly.GetName().Versionアセンブリの論理的な識別用
<FileVersion>fvi.FileVersionWin32ファイルシステム上のバージョン
<Description>fvi.FileDescriptionファイルの説明

設定例:

XML
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    
    <!-- バージョン情報の設定 -->
    <Version>1.2.3-beta</Version>
    <AssemblyVersion>1.2.0.0</AssemblyVersion>
    <FileVersion>1.2.3.4</FileVersion>
    <Authors>Technical Writer</Authors>
    <Company>Sample Tech</Company>
    <Copyright>Copyright © 2024</Copyright>
  </PropertyGroup>
</Project>

このように、Versionタグに文字列を指定すると、それが自動的にAssemblyInformationalVersionとして扱われます。

ターゲットフレームワークの判定

プログラムがコンパイルされたターゲットフレームワーク(.NET 8なのか、.NET Standard 2.0なのか等)を動的に取得したい場合は、AppContext.TargetFrameworkNameを使用します。

C#
using System;

class Program
{
    static void Main()
    {
        string? targetFramework = AppContext.TargetFrameworkName;
        Console.WriteLine($"Target Framework: {targetFramework}");
    }
}
実行結果
Target Framework: .NETCoreApp,Version=v8.0

これは「どのランタイムで動いているか」ではなく、「どのターゲットに対してビルドされたか」を示すため、条件分岐で特定のフレームワーク向けに最適化されたロジックを切り替える際に非常に有用です。

実践的な実装例:バージョン情報のサマリー表示

実際のアプリケーション開発では、これら複数の手法を組み合わせて、起動時にシステム情報をログへ出力する「ヘルパークラス」を作成するのが効率的です。

C#
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Diagnostics;

public static class AppDiagnostics
{
    public static void PrintSystemInfo()
    {
        var assembly = Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly();
        var fvi = FileVersionInfo.GetVersionInfo(assembly.Location);

        Console.WriteLine("========================================");
        Console.WriteLine($"アプリケーション名: {fvi.ProductName}");
        Console.WriteLine($"アセンブリバージョン: {assembly.GetName().Version}");
        Console.WriteLine($"ファイルバージョン: {fvi.FileVersion}");
        Console.WriteLine($"製品バージョン: {fvi.ProductVersion}");
        Console.WriteLine("----------------------------------------");
        Console.WriteLine($"OS: {RuntimeInformation.OSDescription} ({RuntimeInformation.OSArchitecture})");
        Console.WriteLine($"ランタイム: {RuntimeInformation.FrameworkDescription}");
        Console.WriteLine($"ターゲット: {AppContext.TargetFrameworkName}");
        Console.WriteLine("========================================");
    }
}

class Program
{
    static void Main()
    {
        AppDiagnostics.PrintSystemInfo();
    }
}
実行結果
========================================
アプリケーション名: VersionMaster
アセンブリバージョン: 1.0.0.0
ファイルバージョン: 1.0.0.0
製品バージョン: 1.0.0-rc1
----------------------------------------
OS: Microsoft Windows 10.0.22631 (X64)
ランタイム: .NET 8.0.2
ターゲット: .NETCoreApp,Version=v8.0
========================================

このように情報をまとめておくことで、ユーザーからの不具合報告を受けた際に、「どのバージョンのアプリが、どのOS上の、どのランタイムで動いていたのか」を一目で特定できるようになります。

OSのバージョンの取得

環境依存の不具合を調査する場合、.NETのバージョンだけでなくOSのバージョンも重要です。

Environment.OSVersionは古くからある手法ですが、最近の.NETでは前述のRuntimeInformation.OSDescriptionの方がより具体的な名称(Windows 11など)を取得しやすい傾向にあります。

C#
// 伝統的なOSVersion取得
OperatingSystem os = Environment.OSVersion;
Console.WriteLine($"Platform: {os.Platform}");
Console.WriteLine($"Version: {os.Version}");

Windows 10と11の判別など、OSのマイナーな差異を特定する必要がある場合は、レジストリや特定のAPIを叩く必要がありますが、一般的なログ目的であればRuntimeInformationで十分です。

まとめ

C#でバージョン情報を取得する方法は多岐にわたりますが、用途に応じて適切なメソッドを選択することが重要です。

  • ランタイムの情報を知りたい場合は、RuntimeInformation.FrameworkDescription
  • アセンブリの論理バージョンを扱いたい場合は、Assembly.GetName().Version
  • 製品名やコピーライト、詳細な製品バージョンを表示したい場合は、FileVersionInfo
  • ビルド時のターゲットを確認したい場合は、AppContext.TargetFrameworkName

これらの情報を適切に取得し、ログやUIに表示させることで、アプリケーションの保守性は格段に向上します。

特に昨今の高速な.NETのアップデートサイクルにおいては、実行環境の正確な把握はトラブルシューティングの第一歩となります。

ぜひ、自身のプロジェクトに最適なバージョン取得ロジックを組み込んでみてください。