次の方法で共有


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

情報属性を使用して、メソッドの呼び出し元に関する情報を取得します。 ソース コードのファイル パス、ソース コードの行番号、および呼び出し元のメンバー名を取得します。 メンバーの呼び出し元情報を取得するには、省略可能なパラメーターに適用される属性を使用します。 各省略可能なパラメーターは既定値を指定します。 次の表に、 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")。
属性コンストラクター 属性が適用されるメソッドまたはプロパティの名前。 属性がメンバー内の要素 (パラメーター、戻り値、ジェネリック型パラメーターなど) の場合、この結果はその要素に関連付けられているメンバーの名前になります。
メンバーを含まない (アセンブリ レベルや型に適用される属性など) 省略可能なパラメーターの既定値。

引数式

式を引数として渡す場合は、 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;
    }
}

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

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

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

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

こちらも参照ください