実行可能ファイルやアセンブリのバージョン情報に関する属性、その情報を取得する方法について。

§1 バージョン情報に関する属性

アセンブリにバージョン情報を埋め込むための属性と、その意味は次のとおり。

アセンブリのバージョン情報に関する属性
属性 意味・役割
AssemblyVersion アセンブリのバージョン。 構成ファイルを使ったバージョン指定や、アセンブリがGACで管理される場合に使用される値。
major.minor.build.revisionの形式でバージョンを指定する。 buildrevisionにはワイルドカード*を指定することができ、コンパイラに自動的に値を決定させることができる。 (例:"1.0.*.*")
AssemblyFileVersion ファイルのバージョン。 Win32 EXE/DLLとしてのバージョン。 プロパティダイアログで表示されるファイルバージョンを指定したい場合はこの属性を使用する。
major.minor.build.revisionの形式でバージョンを指定する。
AssemblyInformationalVersionAttribute 追加的なバージョン情報、ユーザー向けに表示されるバージョン情報を指定する。
major.minor.build.revision以外の形式のほか、任意の文字列を指定することができる。 (例:"1.0 beta")

§2 アセンブリのバージョン情報を取得する (AssemblyVersionAttribute)

Assembly.GetNameメソッドを使ってバージョン情報を取得したいアセンブリのAssemblyNameを取得し、AssemblyName.Versionプロパティを参照すればアセンブリのバージョン情報を取得できる。 このプロパティでは、バージョン情報をVersionクラス型で取得することができる。

using System;
using System.Reflection;

[assembly: AssemblyVersion("1.2.*")]

class Sample {
  static void Main()
  {
    // 現在実行しているアセンブリ(.exeのアセンブリ)を取得する
    var assm = Assembly.GetExecutingAssembly();

    // AssemblyNameを取得する
    var name = assm.GetName();

    // 名前とバージョンを取得して表示する
    Console.WriteLine("{0} {1}", name.Name, name.Version);
  }
}
.NET Frameworkでの実行結果
E:\>csc /out:TestApplication.exe test.cs & TestApplication.exe

TestApplication 1.2.4834.43060
Monoでの実行結果
$ mcs -out:TestApplication.exe test.cs && mono TestApplication.exe 

TestApplication 1.2.4834.42292

AssemblyVersion属性でアスタリスクを使ってバージョンを指定した場合は、ビルド時の時間を元に自動的に決定される。

§3 アセンブリのファイルバージョン情報を取得する (AssemblyFileVersionAttribute, FileVersionInfo)

AssemblyVersion属性で指定されているバージョン情報ではなく、ファイルに記録されているバージョン情報、もしくはAssemblyFileVersion属性で指定されているバージョン情報を取得したい場合は、FileVersionInfo.GetVersionInfoメソッドを使うことができる。 このメソッドは任意のexeファイル・dllファイルのバージョン情報を取得できるが、Assembly.CodeBaseプロパティを参照してアセンブリのファイルパスを指定することでアセンブリのファイルバージョン情報を取得できる。

なお、Assembly.CodeBaseプロパティが返す値はfile://スキーム形式のURLなので、Uriクラスに変換した後Uri.LocalPathプロパティを参照してパス部分のみを取得する必要がある。

using System;
using System.Diagnostics;
using System.Reflection;

[assembly: AssemblyVersion("1.2.*")]
[assembly: AssemblyFileVersion("4.3.2.1")]

class Sample {
  static void Main()
  {
    // 現在実行しているアセンブリ(.exeのアセンブリ情報)を取得する
    var assm = Assembly.GetExecutingAssembly();

    // アセンブリのファイルパスを取得する
    var path = (new Uri(assm.CodeBase)).LocalPath;

    // アセンブリのFileVersionInfoを取得する
    var versionInfo = FileVersionInfo.GetVersionInfo(path);

    // ファイル名とバージョンを取得して表示する
    Console.WriteLine("{0} {1}", versionInfo.FileName, versionInfo.FileVersion);
  }
}
.NET Frameworkでの実行結果
E:\>csc /out:TestApplication.exe test.cs & TestApplication.exe

E:\TestApplication.exe 4.3.2.1
Monoでの実行結果
$ mcs -out:TestApplication.exe test.cs && mono TestApplication.exe 

/home/smdn/TestApplication.exe 1.2.4834.41152

FileVersionInfo.FileVersionプロパティでは、バージョン情報を文字列型で取得することができる。

なお、Application.ProductVersionプロパティを参照することでもこれと同じバージョン情報を取得することができる。 ただし、このプロパティはAssemblyInformationalVersion属性が指定されている場合はその値を返す。

using System;
using System.Reflection;
using System.Windows.Forms;

[assembly: AssemblyVersion("1.2.*")]
[assembly: AssemblyFileVersion("4.3.2.1")]
[assembly: AssemblyInformationalVersion("9.9.9.9")]

class Sample {
  static void Main()
  {
    // Applicationクラスのプロパティを参照してバージョン情報を取得する
    Console.WriteLine("{0} {1}", Application.ProductName, Application.ProductVersion);
  }
}
.NET Frameworkでの実行結果
E:\>csc /out:TestApplication.exe test.cs & TestApplication.exe

Sample 9.9.9.9
Monoでの実行結果
$ mcs -out:TestApplication.exe -r:System.Windows.Forms.dll test.cs && mono TestApplication.exe 

Sample 9.9.9.9

さらに、AssemblyInformationalVersion属性では「major.minor.build.revision」以外の形式で任意の文字列を指定することが許容される。 そのためApplication.ProductVersionプロパティで取得される値は、必ずしもVersionクラスに変換できるとは限らないので注意する必要がある。

using System;
using System.Reflection;
using System.Windows.Forms;

[assembly: AssemblyVersion("1.2.*")]
[assembly: AssemblyFileVersion("4.3.2.1")]
[assembly: AssemblyInformationalVersion("1.0 beta")] // major.minor.build.revisionの形式ではないバージョン表記を指定する

class Sample {
  static void Main()
  {
    Console.WriteLine("{0} {1}", Application.ProductName, Application.ProductVersion);

    // Application.ProductVersionで得られるバージョンをVersionクラスに変換する
    var version = Version.Parse(Application.ProductVersion); // FormatExceptionがスローされる
  }
}

§4 属性からバージョン情報を取得する

Attribute.GetCustomAttributesメソッドを使ってアセンブリに指定されている属性を取得することでもバージョン情報を取得することはできる。 ただし、この方法ではAssemblyVersion属性を取得することはできない(GetCustomAttributesメソッドは空の配列を返す)。

using System;
using System.Reflection;
using System.Linq;

[assembly: AssemblyVersion("1.2.*")]
[assembly: AssemblyFileVersion("4.3.2.1")]
[assembly: AssemblyInformationalVersion("9.9.9.9")]

class Sample {
  static void Main()
  {
    // 現在実行しているアセンブリ(.exeのアセンブリ)を取得する
    var assm = Assembly.GetExecutingAssembly();

    // AssemblyFileVersion属性を取得する
    var assemblyFileVersion = (AssemblyFileVersionAttribute)Attribute.GetCustomAttributes(assm, typeof(AssemblyFileVersionAttribute)).First();

    Console.WriteLine("AssemblyFileVersion: {0}", assemblyFileVersion.Version);

    // AssemblyInformationalVersion属性を取得する
    var assemblyInformationalVersion = (AssemblyInformationalVersionAttribute)Attribute.GetCustomAttributes(assm, typeof(AssemblyInformationalVersionAttribute)).First();

    Console.WriteLine("AssemblyInformationalVersion: {0}", assemblyInformationalVersion.InformationalVersion);

    // AssemblyVersion属性を取得しようとする (実際には取得できない)
    var assemblyVersion = (AssemblyVersionAttribute)Attribute.GetCustomAttributes(assm, typeof(AssemblyVersionAttribute)).First();

    Console.WriteLine("AssemblyVersionAttribute: {0}", assemblyVersion.Version);
  }
}
.NET Frameworkでの実行結果
E:\>csc /out:TestApplication.exe test.cs & TestApplication.exe

AssemblyFileVersion: 4.3.2.1
AssemblyInformationalVersion: 9.9.9.9

ハンドルされていない例外: System.InvalidOperationException: シーケンスに要素が含まれていません
   場所 System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
   場所 Sample.Main()
Monoでの実行結果
$ mcs test.cs -out:TestApplication.exe && mono TestApplication.exe 

AssemblyFileVersion: 4.3.2.1
AssemblyInformationalVersion: 9.9.9.9

Unhandled Exception:
System.InvalidOperationException: Sequence contains no elements
  at System.Linq.Enumerable.First[Attribute] (IEnumerable`1 source) [0x00000] in <filename unknown>:0 
  at Sample.Main () [0x00000] in <filename unknown>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidOperationException: Sequence contains no elements
  at System.Linq.Enumerable.First[Attribute] (IEnumerable`1 source) [0x00000] in <filename unknown>:0 
  at Sample.Main () [0x00000] in <filename unknown>:0