Determinare le informazioni sul chiamante usando gli attributi interpretati dal compilatore C#

Usando gli attributi delle informazioni, si ottengono informazioni sul chiamante a un metodo. Si ottiene il percorso del file del codice sorgente, il numero di riga nel codice sorgente e il nome del membro del chiamante. È possibile ottenere informazioni sul chiamante usando gli attributi applicati ai parametri facoltativi. Ogni parametro facoltativo specifica un valore predefinito. Nella tabella seguente sono elencati gli attributi di informazioni sul chiamante definiti nello spazio dei nomi System.Runtime.CompilerServices:

Attributo Descrizione Tipo
CallerFilePathAttribute Percorso completo del file di origine contenente il chiamante. Il percorso completo è il percorso in fase di compilazione. String
CallerLineNumberAttribute Numero di riga nel file di origine da cui viene chiamato il metodo. Integer
CallerMemberNameAttribute Nome di una proprietà o di un metodo del chiamante. String
CallerArgumentExpressionAttribute Rappresentazione di stringa dell'espressione dell'argomento. String

Queste informazioni consentono di tracciare e eseguire il debug e consentono di creare strumenti di diagnostica. Nell'esempio seguente viene illustrato come usare gli attributi delle informazioni sul chiamante. In ogni chiamata al metodo TraceMessage, le informazioni sul chiamante vengono inserite per gli argomenti ai parametri facoltativi.

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

Specificare un valore predefinito esplicito per ogni parametro facoltativo. Non è possibile applicare attributi di informazioni sul chiamante ai parametri non specificati come facoltativi. Gli attributi delle informazioni sul chiamante non rendono facoltativo un parametro. ma influiscono sul valore predefinito passato quando l'argomento è omesso. I valori delle informazioni sul chiamante vengono generati come valori letterali nel linguaggio intermedio (IL) in fase di compilazione. A differenza dei risultati della proprietà StackTrace per le eccezioni, i risultati non sono interessati da offuscamento. È possibile fornire esplicitamente gli argomenti facoltativi per esaminare o nascondere le informazioni sul chiamante.

Nomi dei membri

È possibile utilizzare l'attributo CallerMemberName per specificare il nome del membro come argomento String al metodo chiamato. Usando questa tecnica, si evita il problema per cui il refactoring di ridenominazione non modifica i valori String. Questo vantaggio è particolarmente utile per le attività seguenti:

  • Utilizzo della tracciatura e delle routine di diagnostica.
  • Implementazione dell'interfaccia INotifyPropertyChanged durante l'associazione dei dati. Questa interfaccia consente alla proprietà di un oggetto di notificare a un controllo associato che la proprietà è stata modificata. Il controllo può visualizzare le informazioni aggiornate. Senza l'attributo CallerMemberName, è necessario specificare il nome della proprietà come valore letterale.

Nel grafico seguente vengono mostrati i nomi dei membri restituiti quando si utilizza l'attributo CallerMemberName.

Le chiamate si verificano all'interno Nome del membro restituito
Metodo, proprietà o evento Nome del metodo, della proprietà o dell'evento da cui la chiamata ha avuto origine.
Costruttore Stringa ".ctor"
Costruttore statico Stringa ".cctor"
Finalizer Stringa "Finalize"
Operatori o conversioni definiti dall'utente Nome generato per il membro, ad esempio "op_Addition".
Costruttore dell'attributo Nome del metodo o della proprietà cui viene applicato l'attributo. Se l'attributo è un qualsiasi elemento in un membro (ad esempio un parametro, un valore restituito o un parametro di tipo generico), il risultato è il nome del membro associato a tale elemento.
Nessun membro contenitore (ad esempio a livello di assembly o attributi applicati a tipi) Valore predefinito del parametro facoltativo.

Espressioni di argomento

Usare System.Runtime.CompilerServices.CallerArgumentExpressionAttribute quando si desidera che l'espressione sia passata come argomento. È possibile che le librerie di diagnostica forniscano altri dettagli sulle espressioni passate agli argomenti. Fornendo l'espressione che ha attivato la diagnostica, oltre al nome del parametro, gli sviluppatori hanno maggiori dettagli sulla condizione che ha attivato la diagnostica. Queste informazioni aggiuntive semplificano la correzione.

Nell'esempio seguente viene illustrato come fornire informazioni dettagliate sull'argomento quando non è valido:

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

È necessario richiamarlo come illustrato nell'esempio seguente:

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

L'espressione utilizzata per condition viene inserita dal compilatore nell'argomento message. Quando uno sviluppatore chiama Operation con un argomento null, il messaggio seguente viene archiviato nel ArgumentException:

Argument failed validation: <func is not null>

Questo attributo consente di scrivere utilità di diagnostica che forniscono altri dettagli. Gli sviluppatori possono comprendere più rapidamente quali modifiche sono necessarie. È anche possibile usare CallerArgumentExpressionAttribute per determinare quale espressione è stata usata come ricevitore per i metodi di estensione. Il metodo seguente esegue l'esempio di una sequenza a intervalli regolari. Se la sequenza ha meno elementi della frequenza, segnala un errore:

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

Nell'esempio precedente viene usato l'operatore nameof per il parametro sequence. Questa funzionalità è disponibile in C# 11. Prima di C# 11, sarà necessario digitare il nome del parametro come stringa. È possibile chiamare questo metodo come segue:

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

L'esempio precedente genera un oggetto ArgumentException il cui messaggio è il testo seguente:

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

Vedi anche