Bestimmen von Aufruferinformationen mithilfe von Attributen, die vom C#-Compiler interpretiert werden

Mithilfe der Informationsattribute können Sie Informationen zum Aufrufer einer Methode abrufen. Sie können den Dateipfad des Quellcodes, die Zeilennummer im Quellcode und den Membernamen des Aufrufers abrufen. Um diese Memberaufruferinformationen zu erhalten, verwenden Sie die Attribute, die auf optionale Parameter angewendet werden. Jeder optionale Parameter gibt einen Standardwert an. In der folgenden Tabelle sind die Aufrufer-Informationsattribute angegeben, die im System.Runtime.CompilerServices-Namespace definiert sind:

Attribut BESCHREIBUNG Typ
CallerFilePathAttribute Vollständiger Pfad der Quelldatei, die den Aufrufer enthält. Der vollständige Pfad zum Zeitpunkt der Kompilierung. String
CallerLineNumberAttribute Zeilennummer in der Quelldatei, in der die Methode aufgerufen wird Integer
CallerMemberNameAttribute Der Methoden- oder Eigenschaftenname des Aufrufers String
CallerArgumentExpressionAttribute Eine Zeichenfolgendarstellung des Ausdrucks String

Diese Informationen helfen Ihnen bei der Ablaufverfolgung und beim Debuggen und beim Erstellen von Diagnosetools. Im folgenden Beispiel wird die Verwendung der Aufruferinformationsattribute für Aufrufer veranschaulicht. Bei jedem Aufruf der TraceMessage-Methode werden die Aufruferinformationen für die Argumente für optionale Parameter eingefügt.

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

Sie geben einen expliziten Standardwert für jeden optionalen Parameter an. Sie können Aufruferinformationsattribute nicht auf Parameter anwenden, die nicht als optional festgelegt wurden. Durch die Aufruferinformationsattribute wird ein Parameter nicht optional. Stattdessen beeinflussen sie den Standardwert, der beim Auslassen des Arguments übergeben wird. Aufruferinformationswerte werden zur Kompilierzeit als Literale in Intermediate Language (IL) ausgegeben. Im Gegensatz zu den Ergebnissen der StackTrace-Eigenschaft für Ausnahmen werden die Ergebnisse nicht durch Verbergen beeinflusst. Sie können die optionalen Argumente explizit angeben, um die Aufruferinformationen zu steuern oder auszublenden.

Membernamen

Sie können das CallerMemberName-Attribut verwenden, um den Membernamen nicht als String-Argument für die aufgerufene Methode angeben zu müssen. Auf diese Weise umgehen Sie das Problem, dass durch die Umgestaltung mit Umbenennung die String-Werte nicht geändert werden. Dieser Vorteil ist für die folgenden Aufgaben besonders hilfreich:

  • Verwenden der Ablaufverfolgung und der Diagnoseprogramme
  • Implementieren der INotifyPropertyChanged-Schnittstelle beim Binden von Daten Mit dieser Schnittstelle kann die Eigenschaft eines Objekts ein gebundenes Steuerelement benachrichtigen, dass sich die Eigenschaft geändert hat. Das Steuerelement kann die aktualisierten Informationen anzeigen. Ohne das CallerMemberName-Attribut müssen Sie den Eigenschaftennamen als Literal angeben.

Im folgenden Diagramm sind die Membernamen aufgeführt, die beim Verwenden des CallerMemberName-Attributs zurückgegeben werden.

Aufrufe erfolgen in: Membernamenergebnis
Methode, Eigenschaft oder Ereignis Der Name der Methode, der Eigenschaft oder des Ereignisses, aus dem bzw. aus der der Aufruf stammt.
Konstruktor Die Zeichenfolge „.ctor“
Statischer Konstruktor Die Zeichenfolge „.cctor“
Finalizer Die Zeichenfolge „Finalize“
Benutzerdefinierte Operatoren oder Konvertierungen Der generierte Name für den Member, beispielsweise „op_Addition“.
Attributkonstruktor Der Name der Methode oder Eigenschaft, auf die das Attribut angewendet wird. Wenn das Attribut ein beliebiges Element in einem Member ist (z. B. ein Parameter, ein Rückgabewert oder ein generischer Typparameter), wird als Ergebnis der Name des Members ausgegeben, der diesem Element zugeordnet ist.
Kein enthaltender Member (z. B. auf Assemblyebene oder Attribute, die auf Typen angewendet werden) Der Standardwert des optionalen Parameters.

Argumentausdrücke

Verwenden Sie System.Runtime.CompilerServices.CallerArgumentExpressionAttribute, wenn der Ausdruck als Argument übergeben werden soll. Diagnosebibliotheken sollten weitere Details zu den an Argumente übergebenen Ausdrücken bereitstellen. Durch die Bereitstellung des Ausdrucks, der die Diagnose ausgelöst hat, verfügen Entwickler zusätzlich zum Parameternamen weitere Details zur Bedingung, die die Diagnose ausgelöst hat. Diese zusätzlichen Informationen erleichtern die Behebung.

Das folgende Beispiel zeigt, wie Sie ausführliche Informationen zum Argument bereitstellen können, wenn es ungültig ist:

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

Sie würden es wie im folgenden Beispiel gezeigt aufrufen:

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

Der Ausdruck, der für condition verwendet wird, wird vom Compiler in das message-Argument eingefügt. Wenn ein Entwickler Operation mit einem null-Argument aufruft, wird die folgende Meldung in ArgumentException gespeichert:

Argument failed validation: <func is not null>

Mit diesem Attribut können Sie Diagnosehilfsprogramme schreiben, die weitere Details bereitstellen. Entwickler können schneller verstehen, welche Änderungen erforderlich sind. Sie können auch CallerArgumentExpressionAttribute verwenden, um zu bestimmen, welcher Ausdruck als Empfänger für Erweiterungsmethoden verwendet wurde. Mit der folgenden Methode wird in regelmäßigen Abständen eine Sequenz entnommen. Wenn die Sequenz weniger Elemente als die Häufigkeit aufweist, wird ein Fehler gemeldet:

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;
    }
}

Im obigen Beispiel wird der nameof-Operator für den Parameter sequence verwendet. Dieses Feature steht in C# 11 zur Verfügung. Vor C# 11 müssen Sie den Namen des Parameters als Zeichenfolge eingeben. Sie können diese Methode wie folgt aufrufen:

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

Im vorherigen Beispiel wird eine ArgumentException ausgelöst, deren Nachricht den folgenden Text enthält:

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

Siehe auch