C#の開発において、実行中のクラス名を取得したい場面は多岐にわたります。

ログ出力やエラーハンドリング、あるいはリフレクションを用いた動的な処理の実装において、クラス名は非常に重要な情報となります。

本記事では、2026年時点での最新のC#開発環境において、クラス名を取得するための主要な手法とその使い分けを詳しく解説します。

開発効率を高め、保守性の高いコードを書くためのテクニックを学んでいきましょう。

nameof演算子によるクラス名の取得

C#でクラス名を文字列として取得する最もシンプルかつ推奨される方法が、nameof演算子を使用することです。

nameof演算子は、コンパイル時に指定したシンボルの名前を文字列定数として評価します。

C#
public class SampleService
{
    public void Execute()
    {
        // クラス名を文字列として取得
        string className = nameof(SampleService);
        Console.WriteLine($"実行中のクラス: {className}");
    }
}
実行結果
実行中のクラス: SampleService

この手法の最大のメリットは、実行時のオーバーヘッドが全く発生しない点にあります。

また、Visual StudioなどのIDEでクラス名をリファクタリング(名前変更)した際に、nameofの中身も自動的に更新されるため、タイポによるバグを防ぐことができます。

定数として扱われるため、switch文のケースラベルなどにも使用できる非常に強力な機能です。

nameof演算子の注意点

nameof演算子は静的に解決されるため、継承関係がある場合に注意が必要です。

親クラスの中でnameof(ParentClass)と記述した場合、子クラスのインスタンスから呼び出しても返ってくるのは親クラスの名前です。

実行時の型に基づいた動的な名前取得が必要な場合は、後述するGetType()メソッドを使用してください。

GetTypeメソッドによる動的なクラス名取得

実行時のインスタンスが実際にどのクラスであるかを知りたい場合は、Object.GetType()メソッドを使用します。

すべてのC#オブジェクトはGetType()メソッドを継承しており、これによって型情報(Typeオブジェクト)にアクセスできます。

C#
public class BaseClass
{
    public void PrintClassName()
    {
        // 実行時の型情報を取得
        string className = this.GetType().Name;
        Console.WriteLine($"クラス名: {className}");
    }
}

public class SubClass : BaseClass { }

// 実行例
var myObj = new SubClass();
myObj.PrintClassName();
実行結果
クラス名: SubClass

このように、継承先の子クラス名を取得したい場合には、GetType()が非常に有効です。

Name、FullName、Namespaceの使い分け

Typeオブジェクトからは、さまざまな形式で名前を取得できます。

用途に合わせて適切なプロパティを選択しましょう。

プロパティ説明出力例
Nameクラス名のみを取得します。MyClass
FullName名前空間を含む完全修飾名を取得します。MyApp.Models.MyClass
Namespaceクラスが属する名前空間のみを取得します。MyApp.Models

ログ出力などでは、一意性を確保するために FullName を使用するのが一般的です。

typeof演算子による型指定での取得

インスタンスが存在しない状態で、特定の型からクラス名を取得したい場合はtypeof演算子を使用します。

これはジェネリックメソッド内などで特定の型パラメータの名前を知りたいときにも便利です。

C#
// 型から直接名前を取得
string name = typeof(System.Text.StringBuilder).Name;
Console.WriteLine(name);
実行結果
StringBuilder

ジェネリッククラスにおけるクラス名取得の注意点

ジェネリッククラスに対してNameプロパティを使用すると、少し特殊な形式の文字列が返されます。

具体的には、`1`2といった、型パラメータの数を示すバッククォート付きの名前になります。

C#
var listType = typeof(List<string>);
Console.WriteLine(listType.Name);
実行結果
List`1

これを「List<String>」のような人間が読みやすい形式に変換したい場合は、リフレクションを使用して型引数を展開する処理を自作する必要があります。

2026年現在のモダンな開発では、ライブラリ側でこうした整形機能が提供されていることも多いため、自作する前にユーティリティを確認することをお勧めします。

スタティックメソッドやログ出力での実用例

クラス名取得が最も頻繁に使われるのは、ロギングの場面です。

Microsoft.Extensions.Loggingなどを使用する場合、カテゴリー名としてクラス名を渡すことが推奨されています。

C#
public class DataProcessor
{
    private readonly ILogger<DataProcessor> _logger;

    public DataProcessor(ILogger<DataProcessor> logger)
    {
        _logger = logger;
    }

    public void Process()
    {
        // クラス名を明示的に指定せずにログに含める
        _logger.LogInformation("Processing started in {ClassName}", typeof(DataProcessor).Name);
    }
}

依存関係注入(DI)を利用している場合、ジェネリック版のILogger<T>を使えば自動的にクラス名がログカテゴリーになります。

パフォーマンス比較とベストプラクティス

クラス名取得の手法には、パフォーマンスに差があります。

高頻度で呼び出されるループ処理の中などで名前を取得する場合は、手法の選択に注意してください。

  • nameof: 最速。コンパイル時に文字列化されるためコストゼロ。
  • typeof: 高速。Typeオブジェクトの取得にはわずかなコストがかかるが、通常は無視できる。
  • GetType(): 低速。実行時にインスタンスのヘッダを調査するため、最もコストがかかる。

基本的には「可能な限り nameof を使い、動的な型判定が必要な場合のみ GetType() を使う」のがベストプラクティスです。

呼び出し元クラス名の取得(CallerMemberName)

少し特殊なケースとして、メソッドの「呼び出し元」の情報を取得したい場合があります。

System.Runtime.CompilerServices名前空間にある属性を使用すると、引数としてクラス名やメソッド名を自動で注入できます。

C#
public void LogError(string message, [CallerFilePath] string filePath = "")
{
    // filePathにはファイルパスが含まれるため、ここからクラス名を抽出可能
    Console.WriteLine($"Error in {filePath}: {message}");
}

これは主に、デバッグ情報の収集やMVVMパターンでのプロパティ変更通知などに利用されます。

まとめ

C#でクラス名を取得する方法は、用途によって使い分けることが重要です。

静的に確定している場合は nameof を、インスタンスから動的に取得したい場合は GetType().Name を選択しましょう。

また、名前空間を含めた FullName や、ジェネリック型の特殊な表記についても理解しておくことで、デバッグのしやすい堅牢なアプリケーションを構築できます。

2026年以降のモダンなC#開発においても、これらの基本技術は変わらず中心的な役割を果たします。

適切な手法を選び、パフォーマンスと可読性を両立させたコードを目指してください。