次の方法で共有


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

情報属性を使用すると、メソッドの呼び出し元に関する情報を取得できます。 ソース コードのファイル パス、ソース コードの行番号、および呼び出し元のメンバー名を取得できます。 メンバーの呼び出し元情報を取得するには、省略可能なパラメーターに適用する属性を使用します。 各省略可能なパラメーターは既定値を指定します。

C# 言語リファレンスには、C# 言語の最新リリース バージョンが記載されています。 また、今後の言語リリースのパブリック プレビューの機能に関する初期ドキュメントも含まれています。

このドキュメントでは、言語の最後の 3 つのバージョンまたは現在のパブリック プレビューで最初に導入された機能を特定します。

ヒント

C# で機能が初めて導入された時期を確認するには、 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 プロパティの結果とは異なり、難読化は結果に影響しません。 呼び出し元情報を制御したり、呼び出し元情報を非表示にしたりするために、省略可能な引数を明示的に指定できます。

メンバー名

呼び出されたメソッドのString引数としてメンバー名を指定しないようにするには、CallerMemberName属性を使用します。 この手法を使用すると、 リファクタリングの名前変更 によって 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 引数に挿入します。 開発者がOperation引数を使用してnullを呼び出すと、次のメッセージがArgumentExceptionに格納されます。

Argument failed validation: <func is not null>

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

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

前の例では、パラメーター nameofsequence 演算子を使用します。 このメソッドは次のように呼び出します。

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

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

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

こちらも参照ください