Déterminer les informations de l’appelant à l’aide d’attributs interprétés par le compilateur C#

À l'aide des attributs d'informations, vous pouvez obtenir des informations sur l'appelant d'une méthode. Vous pouvez obtenir le chemin d’accès du fichier de code source, le numéro de ligne dans le code source, et le nom du membre de l’appelant. Pour obtenir des informations de membre de l’appelant, vous utilisez les attributs qui sont appliqués aux paramètres facultatifs. Chaque paramètre facultatif spécifie une valeur par défaut. Le tableau suivant répertorie les attributs d'informations de l'appelant définis dans l'espace de noms System.Runtime.CompilerServices :

Attribut Description Type
CallerFilePathAttribute Chemin d’accès complet du fichier source qui contient l’appelant. Le chemin d’accès complet est le chemin d’accès au moment de la compilation. String
CallerLineNumberAttribute Numéro de ligne dans le fichier source à partir duquel la méthode est appelée. Integer
CallerMemberNameAttribute Nom de la méthode ou nom de la propriété de l’appelant. String
CallerArgumentExpressionAttribute Représentation sous forme de chaîne de l’expression d’argument. String

Ces informations vous aident à effectuer un traçage et à déboguer. Elles vous aident également à créer des outils de diagnostic. L'exemple suivant indique comment utiliser des attributs d'informations de l'appelant. À chaque appel à la méthode TraceMessage, les informations de l’appelant sont ajoutées aux arguments des paramètres optionnels.

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

Vous devez spécifier une valeur par défaut explicite pour chaque paramètre optionnel. Vous ne pouvez pas appliquer des attributs d'informations de l'appelant aux paramètres qui ne sont pas spécifiés comme facultatifs. Les attributs d'informations de l'appelant ne rendent pas un paramètre facultatif. À la place, ils affectent la valeur par défaut qui est passée si l'argument est oublié. Les valeurs d'informations de l'appelant sont émises en tant que littéraux en langage intermédiaire (IL) au moment de la compilation. Contrairement aux résultats de la propriété StackTrace pour les exceptions, les résultats ne sont pas affectés par l'obfuscation (protection de code). Vous pouvez fournir explicitement les arguments facultatifs pour contrôler ou masquer des informations de l'appelant.

Noms de membres

Vous pouvez utiliser l'attribut CallerMemberName pour éviter de spécifier le nom du membre comme argument de String à la méthode appelée. Vous évitez ainsi le problème que la refactorisation de changement de nom ne modifie pas les valeurs String. Cet avantage est particulièrement utile pour les tâches suivantes :

  • Utilisation du traçage et des programmes de diagnostic.
  • Implémentation de l'interface INotifyPropertyChanged lors de la liaison de données. Cette interface permet à la propriété d’un objet de signaler à un contrôle dépendant que la propriété a été modifiée. Le contrôle peut afficher les informations mises à jour. Sans attribut CallerMemberName, vous devez spécifier le nom de la propriété comme littéral.

Le graphique suivant affiche les noms des membres qui sont retournés lorsque vous utilisez l'attribut CallerMemberName.

Les appels se produisent à l’intérieur de/d’ Résultat de nom de membre
Méthode, propriété ou événement Le nom de la méthode, la propriété ou l'événement dont l'appel est originaire.
Constructeur La chaîne « .ctor »
Constructeur statique La chaîne « .cctor »
Finaliseur La chaîne « finalize »
Opérateurs définis par l'utilisateur ou conversions Le nom généré pour le membre, par exemple, « op_Addition ».
Constructeur d'attribut Le nom de la méthode ou de la propriété à laquelle s’applique l'attribut. Si l'attribut est un élément dans un membre (tel qu'un paramètre, une valeur de retour, ou un paramètre de type générique), le résultat est le nom du membre qui est associé à cet élément.
Aucun membre contenant (par exemple, niveau assembly ou attributs qui sont appliqués aux types) Valeur par défaut du paramètre optionnel.

Expressions d’argument

Vous utilisez le System.Runtime.CompilerServices.CallerArgumentExpressionAttribute quand vous souhaitez que l’expression passe au statut d’argument. Les bibliothèques de diagnostic peuvent vouloir fournir plus de détails sur les expressions passées au statut d’arguments. En fournissant l’expression qui a déclenché le diagnostic, en plus du nom du paramètre, les développeurs ont plus de détails sur la condition qui a déclenché le diagnostic. Ces informations supplémentaires facilitent la correction.

L’exemple suivant montre comment fournir des informations détaillées sur l’argument lorsqu’il n’est pas valide :

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

Vous pouvez l’appeler comme indiqué dans l’exemple suivant :

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

L’expression utilisée pour la condition est injectée par le compilateur dans l’argument message. Lorsqu’un développeur appelle une Operation avec un argument null, le message suivant est stocké dans ArgumentException :

Argument failed validation: <func is not null>

Cet attribut vous permet de créer des utilitaires de diagnostic qui fournissent plus de détails. Les développeurs peuvent comprendre plus rapidement les modifications nécessaires. Vous pouvez également utiliser le CallerArgumentExpressionAttribute pour déterminer quelle expression a été utilisée comme récepteur pour les méthodes d’extension. La méthode suivante échantillonne une séquence à intervalles réguliers. Si la séquence a moins d’éléments que la fréquence, elle signale une erreur :

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

L’exemple précédent utilise l’opérateur nameof pour le paramètre sequence. Cette fonctionnalité est disponible dans C# 11. Avant C# 11, vous devez taper le nom du paramètre sous forme de chaîne. Vous pouvez appeler cette méthode comme suit :

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

L’exemple précédent lève une classe d’ArgumentException dont le message correspond au texte suivant :

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

Voir aussi