連載
» 2017年12月13日 05時00分 公開

.NET TIPS:クラス名やアセンブリ名を取得するには?[C#/VB]

.NETでクラス名やアセンブリ名を取得するには、nameof/typeof/GetTypeなどの演算子やメソッドを使用する。それらの使い方と差異をまとめる。

[山本康彦,BluewaterSoft/Microsoft MVP for Windows Development]
「.NET TIPS」のインデックス

連載「.NET TIPS」

 クラス名やアセンブリ名を取得する方法とその使い分けを、整理して解説する。

POINT クラス名とアセンブリ情報の取得方法

クラス名とアセンブリ情報の取得方法まとめ クラス名とアセンブリ情報の取得方法まとめ


 特定のトピックをすぐに知りたい方は以下のリンクを活用してほしい。

 なお、nameof演算子はVisual Studio 2015から、その他の演算子やメソッドなどは.NET Frameworkの初期バージョンから利用できるが、本稿に掲載したサンプルコードをそのまま試すにはVisual Studio 2017以降が必要である。また、サンプルコードはコンソールアプリの一部であり、コードの冒頭に以下の宣言が必要となる。

using static System.Console;

Imports System.Console

本稿のサンプルコードに必要な宣言(上:C#、下:VB)

nameof演算子でクラス名などを取得するには?

 Visual Studio 2015で導入されたnameof演算子を使うと、クラス名/メソッド名/変数名/プロパティ名/名前空間名などを取得できる。クラス名を取得する例を次のコードに示す。

public class AAA
{
  public void UseNameof()
    => WriteLine($"クラス名={nameof(AAA)}");
}

public class AAA
  public Sub UseNameof()
    WriteLine($"クラス名={nameof(AAA)}")
    End Sub
End Class

nameof演算子でクラス名を取得する例(上:C#、下:VB)
「nameof(AAA)」の「AAA」は文字列リテラルではない。存在しないクラス名を書くとコンパイルエラーになるので、書き間違いによるバグを防止できる。
詳しくは「.NET TIPS:構文:文字列にクラス名などを間違えないようにコーディングするには?[C# 6.0]」をお読みいただきたい。

 nameof演算子はコンパイル時に文字列リテラルに置き換えられるため、継承したクラスから継承元のUseNameofメソッド(上記サンプルコード)を呼び出しても常に「AAA」となる(次のコード)。

// 上のAAAクラスを継承するクラス
public class BBB : AAA { }

class Program
{
  static void Main(string[] args)
  {
    (new AAA()).UseNameof();
    // 出力:クラス名=AAA
    (new BBB()).UseNameof();
    // 出力:クラス名=AAA

#if DEBUG
    ReadKey();
#endif
  }
}

' 上のAAAクラスを継承するクラス
Public Class BBB
  Inherits AAA
End Class

Module Module1
  Sub Main()
    Dim a As New AAA
    a.UseNameof()
    ' 出力:クラス名=AAA
    Dim b As New BBB
    b.UseNameof()
    ' 出力:クラス名=AAA

#If DEBUG Then
    ReadKey()
#End If
  End Sub
End Module

継承したクラスで呼び出した場合も「AAA」(上:C#、下:VB)

typeof演算子/GetType演算子でクラス名を取得するには?

 クラス名はtypeof演算子(C#)/GetType演算子(Visual Basic、以降VB)を使っても取得できる(次のコード)。この演算子はTypeオブジェクト(System名前空間)を返すので、クラス名を知るにはそのNameプロパティを参照しなければならない。

 この演算子はどのバージョンでも使える。Visual Studio 2015以降では、クラス名だけが欲しいときは前述のnameof演算子、その他の型情報も欲しいときはこの演算子と使い分けることになる。

 この演算子もnameof演算子と同様で、継承先から呼び出しても継承元のクラス名になる。

public class AAA
{
  public void UseTypeof()
    => WriteLine($"クラス名={typeof(AAA).Name}");
}

public class BBB : AAA { }

……省略……

(new AAA()).UseTypeof();
// 出力:クラス名=AAA
(new BBB()).UseTypeof();
// 出力:クラス名=AAA

public class AAA
  Public Sub UseTypeof()
    WriteLine($"クラス名={GetType(AAA).Name}")
  End Sub
End Class

Public Class BBB
  Inherits AAA
End Class

……省略……

Dim a As New AAA
a.UseTypeof()
' 出力:クラス名=AAA
Dim b As New BBB
b.UseTypeof()
' 出力:クラス名=AAA

typeof演算子/GetType演算子でクラス名を取得する例(上:C#、下:VB)

GetTypeメソッドでクラス名を取得するには?

 Objectクラス(System名前空間)のGetTypeメソッドを使うとTypeオブジェクトを取得でき、そのNameプロパティでその型の名前が分かる。すなわち、クラスのインスタンスからクラス名を取得できる(次のコード)。クラスのインスタンスには前述の演算子が使えないので、この方法で取得する。

 GetTypeメソッドは実行時にインスタンスの型情報を取得するので、継承先から呼び出せばその継承先のクラス名になる。

public class AAA
{
  public void UseGetType()
    => WriteLine($"クラス名={this.GetType().Name}");
}

public class BBB : AAA { }

……省略……

(new AAA()).UseGetType();
// 出力:クラス名=AAA
(new BBB()).UseGetType();
// 出力:クラス名=BBB

public class AAA
  Public Sub UseGetType()
    WriteLine($"クラス名={Me.GetType().Name}")
  End Sub
End Class

Public Class BBB
  Inherits AAA
End Class

……省略……

Dim a As New AAA
a.UseGetType()
' 出力:クラス名=AAA
Dim b As New BBB
b.UseGetType()
' 出力:クラス名=BBB

GetTypeメソッドでクラス名を取得する例(上:C#、下:VB)

アセンブリ名を取得するには?(.NET Framework)

 アセンブリ(=exeまたはdllの実行ファイル)の名前などを取得するには、リフレクション(System.Reflection名前空間のAPI)を使う。

 .NET Framework(および、.NET Core 2.0以降)では、TypeオブジェクトのAssemblyプロパティから得られるAssemblyオブジェクト(System.Reflection名前空間)でアセンブリ情報を取得できる(次のコード)。

// クラスが属しているアセンブリのフルネームを取得する
// クラスから
string fullName1 = typeof(AAA).Assembly.FullName;
WriteLine($"アセンブリフルネーム={fullName1}");
// 出力:アセンブリフルネーム=dotNetTips1212LegacyCS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// インスタンスから
string fullName2 = (new AAA()).GetType().Assembly.FullName;
WriteLine($"アセンブリフルネーム={fullName2}");
// 出力:アセンブリフルネーム=dotNetTips1212LegacyCS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

// クラスが属しているアセンブリのパスと名前を取得する
string assemblyPath = typeof(AAA).Assembly.Location;
WriteLine($"アセンブリのパス={assemblyPath}");
// 出力:アセンブリのパス=C:\……省略……\bin\Debug\dotNetTips1212LegacyCS.exe
string assemblyName = System.IO.Path.GetFileNameWithoutExtension(assemblyPath);
WriteLine($"アセンブリ名={assemblyName}");
// 出力:アセンブリ名=dotNetTips1212LegacyCS

' クラスが属しているアセンブリのフルネームを取得する
' クラスから
Dim fullName1 As String = GetType(AAA).Assembly.FullName
WriteLine($"アセンブリフルネーム={fullName1}")
' 出力:アセンブリフルネーム=dotNetTips1212LegacyVB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
' インスタンスから
Dim fullName2 As String = (New AAA).GetType().Assembly.FullName
WriteLine($"アセンブリフルネーム={fullName2}")
' 出力:アセンブリフルネーム=dotNetTips1212LegacyVB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

' クラスが属しているアセンブリのパスと名前を取得する
Dim assemblyPath As String = GetType(AAA).Assembly.Location
WriteLine($"アセンブリのパス={assemblyPath}")
' 出力:アセンブリのパス=C:\……省略……\bin\Debug\dotNetTips1212LegacyVB.exe
Dim assemblyName As String = System.IO.Path.GetFileNameWithoutExtension(assemblyPath)
WriteLine($"アセンブリ名={assemblyName}")
' 出力:アセンブリ名=dotNetTips1212LegacyVB

.NET Frameworkでアセンブリ名などを取得する例(上:C#、下:VB)
前述のtypeof演算子/GetType演算子かGetTypeメソッドを用いて、Typeオブジェクトを得る。TypeオブジェクトのAssemblyプロパティが、その型を含んでいるアセンブリを表すAssemblyオブジェクトである。Assemblyオブジェクトからは、アセンブリのフルネームやパスなどの情報が得られる。
パスの取得のところではクラスからAssemblyを得るコードだけを示したが、もちろんインスタンスからも取得できる。

 なお、リフレクションのMethodBaseクラス(System.Reflection名前空間)を使って実行中のメソッド名の取得も可能ではあるが、Visual Studio 2015以降では前述のnameof演算子を使う方がよい。MethodBaseクラスは実行時にリフレクションを使うのでパフォーマンスに影響が出るが、nameof演算子はコンパイル時に解決されるのだ。

アセンブリ名を取得するには?(.NET Core/UWP)

 .NET Core(2.0未満)では、上記のリフレクションを使ったコードはコンパイルできない。TypeクラスにAssemblyプロパティがないのだ。代わりに、IntrospectionExtensionsクラス(System.Reflection名前空間)のGetTypeInfo拡張メソッドを使う。

 次のコードにC#の例を示す。

using System.Reflection; // GetTypeInfo拡張メソッドの利用に必要
using static System.Console;

class Program
{
  static void Main(string[] args)
  {
    // .NET Core 2.0未満では、この指定をしないとシフトJISが使えない
    System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);

    // クラスが属しているアセンブリ(=実行ファイル)のフルネームを取得する
    // クラス定義から
    string fullName1 = typeof(AAA).GetTypeInfo().Assembly.FullName;
    WriteLine($"アセンブリフルネーム={fullName1}");
    // 出力:アセンブリフルネーム=dotNetTips1212CoreCS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    // インスタンスから
    string fullName2 = (new AAA()).GetType().GetTypeInfo().Assembly.FullName;
    WriteLine($"アセンブリフルネーム={fullName2}");
    // 出力:アセンブリフルネーム=dotNetTips1212CoreCS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

    // クラスが属しているアセンブリのパスと名前
    string assemblyPath = typeof(AAA).GetTypeInfo().Assembly.Location;
    WriteLine($"アセンブリのパス={assemblyPath}");
    // 出力:アセンブリのパス=C:\……省略……\bin\Debug\netcoreapp1.1\dotNetTips1212CoreCS.dll
    string assemblyName = System.IO.Path.GetFileNameWithoutExtension(assemblyPath);
    WriteLine($"アセンブリ名={assemblyName}");
    // 出力:アセンブリ名=dotNetTips1212CoreCS

#if DEBUG
    ReadKey();
#endif
  }
}

.NET Core(2.0未満)でアセンブリ名などを取得する例(C#)
このコードは.NET Core 1.0で動作する。
コンソールアプリでは、NuGetからSystem.Text.Encoding.CodePagesパッケージをインストールしておく必要がある(UWPでは不要)。
Assemblyオブジェクトを取得した後は、前述の.NET Frameworkの場合と同じだ。

 なお、上のコードのコメントにも書いたが、.NET Core(2.0未満)のアプリでは、そのままではシフトJISを扱えない(コンソールアプリはシフトJISで出力しようとするので文字化けする)。その対応として、NuGetからSystem.Text.Encoding.CodePagesパッケージをインストールし(UWPでは不要)、Windowsシステムが持っている全てのエンコーディングを有効にする宣言をプログラムの先頭で行う必要がある(詳しくは「WinRT/Metro TIPS:シフトJISのEncodingオブジェクトを取得するには?[Windows 10 UWPアプリ開発]」参照)。

まとめ

 クラス名を取得するには、3通りの方法がある。

  • クラスに対してnameof演算子を使う(Visual Studio 2015以降)
  • クラスに対してtypeof演算子/GetType演算子を使い、Typeオブジェクトを得る
  • インスタンスに対してGetTypeメソッドを使い、Typeオブジェクトを得る

 アセンブリの情報を取得するには、リフレクションを使ってTypeオブジェクトからAssemblyオブジェクトを得る。.NET Framework(および.NET Core 2.0以降)と.NET Core 2.0未満では、その方法が異なる。

利用可能バージョン:.NET Framework 1.0以降(nameof演算子はVisual Studio 2015以降)
カテゴリ:C# 処理対象:言語構文
カテゴリ:Visual Basic 処理対象:言語構文
カテゴリ:クラス・ライブラリ 処理対象:リフレクション
カテゴリ:C# 処理対象:オブジェクト
カテゴリ:Visual Basic 処理対象:オブジェクト
使用ライブラリ:Objectクラス(System名前空間)
使用ライブラリ:Typeクラス(System名前空間)
使用ライブラリ:Assemblyクラス(System.Reflection名前空間)
使用ライブラリ:IntrospectionExtensionsクラス(.NET CoreのSystem.Reflection名前空間)
関連TIPS:構文:文字列にクラス名などを間違えないようにコーディングするには?[C# 6.0]
関連TIPS:メソッドやプロパティの有無を確認して呼び出すには?
関連TIPS:文字列で指定したクラスのインスタンスを作成するには?
関連TIPS:文字列で指定したメソッドを呼び出すには?
関連TIPS:構文:メソッドやプロパティをラムダ式で簡潔に実装するには?[C# 6.0/7.0]
関連TIPS:構文:クラス名を書かずに静的メソッドを呼び出すには?[C# 6.0]
関連TIPS:VB.NETでクラス名を省略してメソッドや定数を利用するには?
関連TIPS:数値を右詰めや0埋めで文字列化するには?[C#、VB]
関連TIPS:Visual Studioでコンソール・アプリケーションのデバッグ実行時にコマンド・プロンプトを閉じないようにするには?


「.NET TIPS」のインデックス

.NET TIPS

Copyright© 1999-2018 Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。