web-dev-qa-db-fra.com

Meilleur moyen de vérifier les paramètres nuls (clauses de garde)

Par exemple, vous ne voulez généralement pas que les paramètres d'un constructeur soient nuls. Il est donc très normal de voir quelque chose comme

if (someArg == null)
{
    throw new ArgumentNullException(nameof(someArg));
}

if (otherArg == null)
{
    throw new ArgumentNullException(nameof(otherArg));
}

Il encombre un peu le code.  

Est-il possible de vérifier un argument d'une liste d'arguments mieux que cela?

Quelque chose comme "vérifie tous les arguments et lève une exception ArgumentNullException si l’un d’eux est null et que cela vous fournit les arguments nuls.

En passant, en ce qui concerne les revendications de questions en double, il ne s'agit pas de marquer des arguments avec des attributs ou de quelque chose qui est intégré, mais ce que certains appellent des clauses de garde pour garantir qu'un objet reçoit des dépendances initialisées.

14
SuperJMN
public static class Ensure
{
    /// <summary>
    /// Ensures that the specified argument is not null.
    /// </summary>
    /// <param name="argumentName">Name of the argument.</param>
    /// <param name="argument">The argument.</param>
    [DebuggerStepThrough]
    [ContractAnnotation("halt <= argument:null")]        
    public static void ArgumentNotNull(object argument, [InvokerParameterName] string argumentName)
    {
        if (argument == null)
        {
            throw new ArgumentNullException(argumentName);
        }
    }
}

usage:

// C# < 6
public Constructor([NotNull] object foo)
{
    Ensure.ArgumentNotNull(foo, "foo");
    ...
}

// C# >= 6
public Constructor([NotNull] object bar)
{
    Ensure.ArgumentNotNull(bar, nameof(bar));
    ...
}

La DebuggerStepThroughAttribute est assez pratique pour qu'en cas d'excuse lors du débogage (ou lorsque j'attache le débogueur après que l'exception se soit produite), je ne me retrouverai pas dans la méthode ArgumentNotNull mais plutôt dans la méthode d'appel où la référence null actually se produira.

J'utilise Annotations de contrat ReSharper

  • La ContractAnnotationAttribute s'assure que je ne mal orthographie jamais L'argument ("foo") et le renomme automatiquement si je renomme Le symbole foo
  • La NotNullAttribute aide ReSharper à analyser le code. Donc, si je fais new Constructor(null) si ReSharper nous avertira que cela entraînera une exception. 
  • Si vous n'aimez pas annoter directement votre code, Vous pouvez également faire la même chose avec fichiers XML externes que vous pouvez déployer avec votre bibliothèque et que les utilisateurs peuvent utiliser comme référence dans ReShaprer.
15
bitbonk

Si vous avez trop de paramètres dans vos constructeurs, vous feriez mieux de les réviser, mais c'est une autre histoire.

Pour diminuer le code de validation standard, beaucoup de personnes écrivent des classes d’utilitaires Guard comme ceci:

public static class Guard
{
    public static void ThrowIfNull(object argumentValue, string argumentName)
    {
        if (argumentValue == null)
        {
            throw new ArgumentNullException(argumentName);
        }
    }

    // other validation methods
}

(Vous pouvez ajouter d'autres méthodes de validation qui pourraient être nécessaires pour cette classe Guard).

Ainsi, il suffit d’une seule ligne de code pour valider un paramètre:

    private static void Foo(object obj)
    {
        Guard.ThrowIfNull(obj, "obj");
    }
11
serge.karalenka

Les références nulles sont un type de problème contre lequel vous devez vous protéger. Mais, ils ne sont pas les seuls. Le problème est plus vaste que cela et se résume à ceci: Method accepte des instances d'un certain type, mais ne peut pas gérer toutes les instances.

En d'autres termes, le domaine de la méthode est plus grand que l'ensemble des valeurs qu'elle gère. Les clauses de garde sont ensuite utilisées pour affirmer que le paramètre réel ne tombe pas dans cette "zone grise" du domaine de la méthode qui ne peut pas être traitée.

Nous avons maintenant des références nulles, en tant que valeur généralement en dehors du jeu de valeurs acceptable. Par ailleurs, il arrive souvent que certains éléments non nuls de l'ensemble soient également inacceptables (par exemple, une chaîne vide).

Dans ce cas, il se peut que la signature de la méthode soit trop large, ce qui indique alors un problème de conception. Cela peut conduire à une refonte, par exemple définissant un sous-type, généralement une interface dérivée, qui restreint le domaine de la méthode et fait disparaître certaines des clauses de garde. Vous trouverez un exemple dans cet article: Pourquoi avons-nous besoin de clauses de garde?

6
Zoran Horvat

Vous pouvez essayer ma Heleonix.Guard library, qui fournit des fonctionnalités de protection.

Vous pouvez écrire des clauses de garde comme ci-dessous:

// C# 7.2+: Non-Trailing named arguments
Throw.ArgumentNullException(when: param.IsNull(), nameof(param));

// OR

// Prior to C# 7.2: You can use a helper method 'When'
Throw.ArgumentNullException(When(param.IsNull()), nameof(param));

// OR
Throw.ArgumentNullException(param == null, nameof(param));

// OR
Throw.ArgumentNullException(When (param == null), nameof(param));

Il permet de lancer de nombreuses exceptions existantes et vous pouvez écrire des méthodes d'extension personnalisées pour les exceptions personnalisées. De plus, la bibliothèque fait référence à la bibliothèque 'Heleonix.Extensions' avec des extensions prédicatives telles que IsNull, IsNullOrEmptyOrWhitespace, IsLessThan et bien d’autres pour vérifier vos arguments ou variables par rapport aux valeurs souhaitées. Contrairement à d'autres bibliothèques de garde avec des interfaces fluides, ces extensions ne génèrent pas d'objets intermédiaires, et comme leur implémentation est vraiment simple, elles sont performantes.

1
Hennadii Lutsyshyn

Il existe un paquet de pépites appelé SwissKnife . Installez SwissKnife à partir de nuget gallery . Il vous offre de nombreuses options, à commencer par la vérification nulle des arguments Argument.IsNotNullOrEmpty(args,"args") sous SwissKnife.Diagnostics.Contracts namespace alongwith avec l'option idoim et plus Vous pouvez définir Option<Class_Name> _someVar, puis vérifier si _someVar.IsSome ou _someVar.IsNone. Cela aide également contre les classes nullable. J'espère que cela t'aides.

1