Compartilhar via


Determinar informações do chamador usando atributos que o compilador C# interpreta

Usando atributos de informações, você pode obter informações sobre o chamador para um método. Você pode obter o caminho do arquivo do código-fonte, o número da linha no código-fonte e o nome do membro do chamador. Para obter informações do chamador de membro, use atributos que você aplica a parâmetros opcionais. Cada parâmetro opcional especifica um valor padrão.

A linguagem C# faz referência a documentos da versão mais recentemente lançada da linguagem C#. Ele também contém a documentação inicial para recursos em visualizações públicas para a próxima versão do idioma.

A documentação identifica qualquer recurso introduzido pela primeira vez nas três últimas versões do idioma ou nas versões prévias públicas atuais.

Dica

Para descobrir quando um recurso foi introduzido pela primeira vez em C#, consulte o artigo sobre o histórico de versão da linguagem C#.

A tabela a seguir lista os atributos de Informações do Chamador definidos no System.Runtime.CompilerServices namespace:

Atributo Descrição Tipo
CallerFilePathAttribute O caminho completo do arquivo de origem que contém o chamador. O caminho completo é o caminho em tempo de compilação. String
CallerLineNumberAttribute Número de linha no arquivo de origem do qual o método é chamado. Integer
CallerMemberNameAttribute Nome do método ou nome da propriedade do chamador. String
CallerArgumentExpressionAttribute Representação de cadeia de caracteres da expressão de argumento. String

Essas informações ajudam você com o rastreamento e a depuração e ajudam você a criar ferramentas de diagnóstico. O exemplo a seguir mostra como usar atributos de informações do chamador. Em cada chamada para o TraceMessage método, as informações do chamador são inseridas para os argumentos para os parâmetros opcionais.

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

Especifique um valor padrão explícito para cada parâmetro opcional. Você não pode aplicar atributos de informações de chamador a parâmetros que não são opcionais. Os atributos de informações do chamador não tornam um parâmetro opcional. Em vez disso, eles afetam o valor padrão passado quando o argumento é omitido. O compilador emite valores de informações do chamador como literais na IL (Linguagem Intermediária) no tempo de compilação. Ao contrário dos resultados da StackTrace propriedade para exceções, a ofuscação não afeta os resultados. Você pode fornecer explicitamente os argumentos opcionais para controlar as informações do chamador ou ocultar informações do chamador.

Nomes dos membros

Use o CallerMemberName atributo para evitar especificar o nome do membro como um String argumento para o método chamado. Ao usar essa técnica, você evita o problema de que a Refatoração de Renomeação não altera os valores de String. Esse benefício é especialmente útil para as seguintes tarefas:

  • Usar rotinas de rastreamento e diagnóstico.
  • Implementando a INotifyPropertyChanged interface ao associar dados. Essa interface permite que a propriedade de um objeto notifique um controle associado de que a propriedade foi alterada. O controle pode exibir as informações atualizadas. Sem o atributo CallerMemberName, você deve especificar o nome da propriedade como um valor literal.

O gráfico a seguir mostra os nomes de membro que são retornados quando você usa o CallerMemberName atributo.

As chamadas ocorrem dentro Resultado de nome de membro
Método, propriedade ou evento O nome do método, propriedade ou evento do qual a chamada se originou.
Construtor A cadeia de caracteres “.ctor”
Construtor estático A cadeia de caracteres “.cctor”
Finalizador A cadeia de caracteres "Finalize"
Operadores ou conversões definidos pelo usuário O nome gerado para o membro, por exemplo, "op_Addition".
Construtor de atributos O nome do método ou propriedade ao qual o atributo é aplicado. Se o atributo for qualquer elemento dentro de um membro (como um parâmetro, um valor retornado ou um parâmetro de tipo genérico), esse resultado será o nome do membro associado a esse elemento.
Nenhum membro contentor (por exemplo, nível de assembly ou atributos que são aplicadas aos tipos) O valor padrão do parâmetro opcional.

Expressões de argumento

Use quando System.Runtime.CompilerServices.CallerArgumentExpressionAttribute quiser que a expressão seja passada como um argumento. As bibliotecas de diagnóstico podem fornecer mais detalhes sobre as expressões passadas para argumentos. Ao fornecer a expressão que disparou o diagnóstico, além do nome do parâmetro, os desenvolvedores têm mais detalhes sobre a condição que disparou o diagnóstico. Essas informações extras facilitam a correção.

O exemplo a seguir mostra como você pode fornecer informações detalhadas sobre o argumento quando ele é inválido:

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

Invoque-o conforme mostrado no exemplo a seguir:

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

O compilador injeta a expressão usada no conditionmessage argumento. Quando um desenvolvedor chama Operation com um null argumento, a seguinte mensagem é armazenada no ArgumentException:

Argument failed validation: <func is not null>

Usando esse atributo, você pode escrever utilitários de diagnóstico que fornecem mais detalhes. Os desenvolvedores podem entender mais rapidamente quais alterações são necessárias. Você também pode usar a CallerArgumentExpressionAttribute para determinar qual expressão foi usada como receptor para membros de extensão. O método a seguir amostra uma sequência em intervalos regulares. Se a sequência tiver menos elementos do que a frequência, ela relatará um erro:

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

O exemplo anterior usa o nameof operador para o parâmetro sequence. Você pode chamar esse método da seguinte maneira:

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

O exemplo anterior gera uma ArgumentException mensagem cuja mensagem é o seguinte texto:

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

Consulte também