Compartir vía


Determinación de la información del autor de la llamada mediante atributos interpretados por el compilador de C#

Mediante atributos de información, se obtiene información sobre el autor de la llamada a un método. Obtiene la ruta de acceso del archivo del código fuente, el número de línea en el código fuente y el nombre del miembro del autor de la llamada. Para obtener la información del llamador del miembro, use los atributos que se aplican a los parámetros opcionales. Cada parámetro opcional especifica un valor predeterminado. En la tabla siguiente se enumeran los atributos de información del llamante que se definen en el System.Runtime.CompilerServices espacio de nombres:

Atributo Descripción Tipo
CallerFilePathAttribute Ruta de acceso completa del archivo de código fuente que contiene el llamador. La ruta de acceso completa es la ruta de acceso en tiempo de compilación. String
CallerLineNumberAttribute Número de línea del archivo de origen desde el que se llama al método . Integer
CallerMemberNameAttribute Nombre del método o nombre de propiedad del autor de la llamada. String
CallerArgumentExpressionAttribute Representación de cadena de la expresión de argumento. String

Esta información le ayuda con el seguimiento y la depuración, y le ayuda a crear herramientas de diagnóstico. En el ejemplo siguiente se muestra cómo usar atributos de información del autor de la llamada. En cada llamada al TraceMessage método , la información del autor de la llamada se inserta para los argumentos en los parámetros opcionales.

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 un valor predeterminado explícito para cada parámetro opcional. No se pueden aplicar atributos de información del autor de la llamada a parámetros que no se especifican como opcionales. Los atributos de información del autor de la llamada no hacen que un parámetro sea opcional. En su lugar, afectan al valor predeterminado pasado cuando se omite el argumento. Los valores de información del autor de la llamada se emiten como literales en el lenguaje intermedio (IL) en tiempo de compilación. A diferencia de los resultados de la StackTrace propiedad para las excepciones, la ofuscación no afecta a los resultados. Puede proporcionar explícitamente los argumentos opcionales para controlar la información del autor de la llamada o ocultar la información del autor de la llamada.

Nombres de miembro

Puede usar el CallerMemberName atributo para evitar especificar el nombre de miembro como argumento String para el método llamado. Mediante esta técnica, se evita el problema de que la refactorización de cambio de nombre no cambie los valores String. Esta ventaja es especialmente útil para las siguientes tareas:

  • Uso de rutinas de seguimiento y diagnóstico.
  • Implementación de la INotifyPropertyChanged interfaz al enlazar datos. Esta interfaz permite que la propiedad de un objeto notifique a un control enlazado que la propiedad ha cambiado. El control puede mostrar la información actualizada. Sin el atributo CallerMemberName, se debe especificar el nombre de propiedad como un literal.

En el gráfico siguiente se muestran los nombres de miembro que se devuelven al usar el CallerMemberName atributo .

Las llamadas se producen dentro de Resultado del nombre de miembro
Método, propiedad o evento Nombre del método, propiedad o evento desde el que se originó la llamada.
Constructor Cadena ".ctor"
Constructor estático Cadena ".cctor"
Finalizador Cadena "Finalize"
Operadores o conversiones definidos por el usuario Nombre generado para el miembro, por ejemplo, "op_Addition".
Constructor de atributos Nombre del método o propiedad al que se aplica el atributo. Si el atributo es cualquier elemento dentro de un miembro (como un parámetro, un valor devuelto o un parámetro de tipo genérico), este resultado es el nombre del miembro asociado a ese elemento.
Ningún miembro contenedor (por ejemplo, nivel de ensamblado o atributos que se aplican a tipos) Valor predeterminado del parámetro opcional.

Expresiones de argumento

Se usa System.Runtime.CompilerServices.CallerArgumentExpressionAttribute cuando se quiere que la expresión se pase como argumento. Las bibliotecas de diagnóstico pueden proporcionar más detalles sobre las expresiones pasadas a argumentos. Al proporcionar la expresión que desencadenó el diagnóstico, además del nombre del parámetro, los desarrolladores tienen más detalles sobre la condición que desencadenó el diagnóstico. Esa información adicional facilita la corrección.

En el ejemplo siguiente se muestra cómo puede proporcionar información detallada sobre el argumento cuando no es válido:

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

Lo invocaría como se muestra en el ejemplo siguiente:

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

El compilador inserta la expresión utilizada para condition en el message argumento . Cuando un desarrollador llama Operation a con un null argumento , el mensaje siguiente se almacena en :ArgumentException

Argument failed validation: <func is not null>

Este atributo permite escribir utilidades de diagnóstico que proporcionan más detalles. Los desarrolladores pueden comprender más rápidamente qué cambios se necesitan. También puede usar CallerArgumentExpressionAttribute para determinar qué expresión se usó como receptor para los miembros de la extensión. En el método siguiente se muestra una secuencia a intervalos regulares. Si la secuencia tiene menos elementos que la frecuencia, notifica un error:

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

En el ejemplo anterior se usa el nameof operador para el parámetro sequence. Puede llamar a este método de la siguiente manera:

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

En el ejemplo anterior se produciría un ArgumentException mensaje cuyo mensaje es el texto siguiente:

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

Consulte también