共用方式為


使用 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”
終結器 字串「完成」
使用者定義的運算子或轉換 成員生成的名稱,例如「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;
        }
    }
}

上述範例使用 nameof 參數 sequence的運算符。 您可以呼叫此方法,如下所示:

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

上述範例會擲回 ArgumentException 其訊息為下列文字的 :

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

另請參閱