C# コンパイラによって解釈される属性を使用して呼び出し元情報を確認する

info 属性を使用して、メソッドの呼び出し元に関する情報を取得します。 ソース コードのファイル パス、ソース コードの行番号、呼び出し元のメンバー名を取得します。 メンバー呼び出し元情報を取得するには、省略可能なパラメーターに適用される属性を使用します。 省略可能な各パラメーターでは既定値が指定されます。 次の表は、System.Runtime.CompilerServices 名前空間で定義されている呼び出し元情報の属性の一覧です。

属性 説明 種類
CallerFilePathAttribute 呼び出し元を含むソース ファイルのフル パスです。 完全なパスは、コンパイル時のパスです。 String
CallerLineNumberAttribute メソッドの呼び出し元であるソース ファイルの行番号。 Integer
CallerMemberNameAttribute 呼び出し元のメソッド名またはプロパティ名。 String
CallerArgumentExpressionAttribute 引数式の文字列表現。 String

この情報はトレースとデバッグに役立ち、診断ツールの作成に役立ちます。 呼び出し元情報の属性を使用する方法の例を次に示します。 TraceMessage メソッドを呼び出すたびに、呼び出し元情報は、省略可能なパラメーターの引数として挿入されます。

public void DoProcessing()
{
    TraceMessage("Something happened.");
}

public void TraceMessage(string message,
        [CallerMemberName] string memberName = "",
        [CallerFilePath] string sourceFilePath = "",
        [CallerLineNumber] int sourceLineNumber = 0)
{
    Trace.WriteLine("message: " + message);
    Trace.WriteLine("member name: " + memberName);
    Trace.WriteLine("source file path: " + sourceFilePath);
    Trace.WriteLine("source line number: " + sourceLineNumber);
}

// Sample Output:
//  message: Something happened.
//  member name: DoProcessing
//  source file path: c:\Visual Studio Projects\CallerInfoCS\CallerInfoCS\Form1.cs
//  source line number: 31

省略可能な各パラメーターには、明示的な既定値を指定します。 省略可能と指定されていないパラメーターには、呼び出し元情報の属性を適用できません。 呼び出し元情報の属性によってパラメーターが省略可能になるわけではありません。 この属性は、引数を省略したときに渡される既定値に影響します。 呼び出し元情報の値は、コンパイル時に中間言語 (IL) 内にリテラルとして出力されます。 例外の StackTrace プロパティの結果とは異なり、難読化による影響は受けません。 省略可能な引数を明示的に指定して、呼び出し元情報を制御したり、非表示にしたりできます。

メンバー名

CallerMemberName 属性を使用して、呼び出されたメソッドにメンバー名を String 引数として指定することを回避できます。 この方法を使用すると、リファクタリングの名前の変更String 値が変更されないという問題が発生しなくなります。 この利点は、次のタスクで役立ちます。

  • トレース ルーチンと診断ルーチンの使用。
  • データ バインディング時の INotifyPropertyChanged インターフェイスの実装。 このインターフェイスでは、オブジェクトのプロパティによって、バインドされたコントロールにプロパティが変更されたことを通知できます。 コントロールでは、更新後の情報を表示できます。 CallerMemberName 属性がない場合は、リテラルとしてプロパティ名を指定する必要があります。

次のグラフは、CallerMemberName 属性の使用時に返されるメンバー名を示します。

呼び出しの発生元 メンバー名の結果
メソッド、プロパティ、またはイベント 呼び出しが発生したメソッド、プロパティ、またはイベントの名前。
コンストラクター 文字列「.ctor」
静的コンストラクター 文字列「.cctor」
ファイナライザー 文字列「Finalize」
ユーザー定義の演算子または変換 生成されたメンバー名 (「op_Addition」など)。
Attribute コンストラクター 属性が適用されるメソッドまたはプロパティの名前。 属性がメンバー内の要素 (パラメーター、戻り値、ジェネリック型パラメーターなど) である場合、この結果は、その要素に関連付けられているメンバーの名前になります。
含んでいないメンバー (型に適用されているアセンブリ レベルや属性など) 省略可能なパラメーターの既定値。

引数式

式を引数として渡す場合、System.Runtime.CompilerServices.CallerArgumentExpressionAttribute を使用します。 診断ライブラリでは、引数に渡される "" に関する詳細情報を提供できます。 パラメーター名に加えて、診断をトリガーした式を指定することで、開発者は診断をトリガーした条件に関する詳細情報を得ることができます。 この追加情報により、修正が容易になります。

次の例は、引数が無効な場合に、その引数に関する詳細情報を提供する方法を示しています。

public static void ValidateArgument(string parameterName, bool condition, [CallerArgumentExpression("condition")] string? message=null)
{
    if (!condition)
    {
        throw new ArgumentException($"Argument failed validation: <{message}>", parameterName);
    }
}

次の例に示すように呼び出します。

public void Operation(Action func)
{
    Utilities.ValidateArgument(nameof(func), func is not null);
    func();
}

condition に使用される式は、コンパイラによって message 引数に挿入されます。 開発者が null 引数を付けて Operation を呼び出すと、次のメッセージが ArgumentException に格納されます。

Argument failed validation: <func is not null>

この属性によって、詳細情報を提供する診断ユーティリティを作成できます。 どのような変更が必要か、開発者は今までより簡単に理解できます。 また、CallerArgumentExpressionAttribute を使用し、拡張メソッドのレシーバーとして使用された式を確認できます。 次のメソッドでは、一定の間隔でシーケンスをサンプリングします。 シーケンスの要素数が頻度よりも少ない場合、次のようなエラーが報告されます。

public static IEnumerable<T> Sample<T>(this IEnumerable<T> sequence, int frequency, 
    [CallerArgumentExpression(nameof(sequence))] string? message = null)
{
    if (sequence.Count() < frequency)
        throw new ArgumentException($"Expression doesn't have enough elements: {message}", nameof(sequence));
    int i = 0;
    foreach (T item in sequence)
    {
        if (i++ % frequency == 0)
            yield return item;
    }
}

前の例では、パラメーター sequence に演算子 nameof を使用しています。 この機能は C# 11 で使用できます。 C# 11 以前の場合、パラメーターの名前を文字列として入力する必要があります。 次のように、このメソッドを呼び出すことができます。

sample = Enumerable.Range(0, 10).Sample(100);

前の例では、メッセージが次のテキストである ArgumentException がスローされます。

Expression doesn't have enough elements: Enumerable.Range(0, 10) (Parameter 'sequence')

関連項目