Określanie informacji o obiekcie wywołującym przy użyciu atrybutów interpretowanych przez kompilator języka C#

Korzystając z atrybutów informacji, uzyskujesz informacje o obiekcie wywołującym metodę. Uzyskujesz ścieżkę pliku kodu źródłowego, numer wiersza w kodzie źródłowym i nazwę elementu członkowskiego obiektu wywołującego. Aby uzyskać informacje o elementach wywołujących składowych, należy użyć atrybutów, które są stosowane do parametrów opcjonalnych. Każdy opcjonalny parametr określa wartość domyślną. W poniższej tabeli wymieniono atrybuty informacji o obiekcie wywołującym System.Runtime.CompilerServices zdefiniowane w przestrzeni nazw:

Atrybut opis Type
CallerFilePathAttribute Pełna ścieżka pliku źródłowego zawierającego obiekt wywołujący. Pełna ścieżka to ścieżka w czasie kompilacji. String
CallerLineNumberAttribute Numer wiersza w pliku źródłowym, z którego jest wywoływana metoda. Integer
CallerMemberNameAttribute Nazwa metody lub nazwa właściwości obiektu wywołującego. String
CallerArgumentExpressionAttribute Reprezentacja ciągu wyrażenia argumentu. String

Te informacje ułatwiają śledzenie i debugowanie oraz ułatwia tworzenie narzędzi diagnostycznych. W poniższym przykładzie pokazano, jak używać atrybutów informacji o obiekcie wywołującym. Na każdym wywołaniu TraceMessage metody informacje wywołujące są wstawione dla argumentów do parametrów opcjonalnych.

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

Należy określić jawną wartość domyślną dla każdego opcjonalnego parametru. Nie można zastosować atrybutów informacji wywołujących do parametrów, które nie są określone jako opcjonalne. Atrybuty informacji o obiekcie wywołującym nie są opcjonalne. Zamiast tego wpływają na domyślną wartość, która jest przekazywana, gdy argument zostanie pominięty. Wartości informacji o obiekcie wywołującym są emitowane jako literały do języka pośredniego (IL) w czasie kompilacji. W przeciwieństwie do wyników StackTrace właściwości wyjątków, wyniki nie mają wpływu na zaciemnianie. Można jawnie dostarczyć opcjonalne argumenty do sterowania informacjami o obiekcie wywołującym lub ukryć te informacje.

Nazwy elementów członkowskich

Możesz użyć atrybutu CallerMemberName , aby uniknąć określania nazwy elementu członkowskiego jako String argumentu do wywoływanej metody. Korzystając z tej techniki, należy uniknąć problemu, który refaktoryzacja zmiany nazwy nie zmienia String wartości. Jest to szczególnie przydatne w następujących zadaniach:

  • Używanie procedur do śledzenia i diagnostycznych.
  • Implementowanie interfejsu INotifyPropertyChanged podczas wiązania danych. Ten interfejs umożliwia właściwości obiektu powiadamianie powiązanej kontrolki o zmianie właściwości. Kontrolka może wyświetlać zaktualizowane informacje. Bez atrybutu CallerMemberName należy określić nazwę właściwości jako literał.

Na poniższym wykresie przedstawiono nazwy elementów członkowskich zwracane podczas używania atrybutu CallerMemberName .

Wywołania występują w obrębie Wynikowa nazwa elementu członkowskiego
Metoda, właściwość lub zdarzenie Nazwa metody, właściwości lub zdarzenia, gdzie zainicjowane było wywołanie.
Konstruktor Ciąg „.ctor”
Statyczny konstruktor Ciąg „.cctor”
Finalizatorów Ciąg „Finalize”.
Zdefiniowane przez użytkownika operatory lub konwersje Nazwa wygenerowana dla elementu członkowskiego, na przykład „op_Addition”.
Konstruktor atrybutu Nazwa metody lub właściwości, do której jest stosowany atrybut. Jeśli atrybut jest dowolnym elementem elementu członkowskiego (takim jak parametr, wartość zwracana lub parametr typu ogólnego), to wynikiem jest nazwa elementu członkowskiego, który jest skojarzony z tym elementem.
Brak nadrzędnego elementu członkowskiego (na przykład poziom zestawu lub atrybuty, które są stosowane do typów) Wartość domyślna opcjonalnego parametru.

Wyrażenia argumentów

System.Runtime.CompilerServices.CallerArgumentExpressionAttribute W przypadku, gdy chcesz, aby wyrażenie było przekazywane jako argument. Biblioteki diagnostyczne mogą chcieć podać więcej szczegółów na temat wyrażeń przekazywanych do argumentów. Podając wyrażenie, które wyzwoliło diagnostykę, oprócz nazwy parametru, deweloperzy mają więcej szczegółów na temat warunku, który wyzwolił diagnostykę. Te dodatkowe informacje ułatwiają naprawienie.

W poniższym przykładzie pokazano, jak można podać szczegółowe informacje o argumencie, gdy jest on nieprawidłowy:

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

Wywołasz go, jak pokazano w poniższym przykładzie:

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

Wyrażenie używane dla condition elementu jest wstrzykiwane przez kompilator do argumentu message . Gdy deweloper wywołuje Operation argument z argumentem null , następujący komunikat jest przechowywany w pliku ArgumentException:

Argument failed validation: <func is not null>

Ten atrybut umożliwia pisanie narzędzi diagnostycznych, które zawierają więcej szczegółów. Deweloperzy mogą szybciej zrozumieć, jakie zmiany są potrzebne. Można również użyć elementu , CallerArgumentExpressionAttribute aby określić, które wyrażenie zostało użyte jako odbiornik dla metod rozszerzeń. Poniższa metoda próbkuje sekwencję w regularnych odstępach czasu. Jeśli sekwencja ma mniej elementów niż częstotliwość, zgłasza błąd:

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

W poprzednim przykładzie użyto nameof operatora dla parametru sequence. Ta funkcja jest dostępna w języku C# 11. Przed użyciem języka C# 11 należy wpisać nazwę parametru jako ciąg. Tę metodę można wywołać w następujący sposób:

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

W powyższym przykładzie zostanie zgłoszony ArgumentException komunikat, którego wiadomość jest następującym tekstem:

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

Zobacz też