web-dev-qa-db-fra.com

C #: Comment implémenter et utiliser un attribut NotNull et CanBeNull

Je veux que les programmeurs et moi-même sachions qu'une méthode ne veut pas de null et si vous lui envoyez quand même null, le résultat ne sera pas joli.

Il y a un NotNullAttribute et un CanBeNullAttribute dans Lokad Shared Libraries , dans le Lokad.Quality espace de noms.

Mais comment ça marche? J'ai regardé le code source de ces deux attributs, et il ressemble à ceci:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter |
                AttributeTargets.Property | AttributeTargets.Delegate |
                AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
[NoCodeCoverage]
public sealed class NotNullAttribute : Attribute
{
}

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter |
                AttributeTargets.Property | AttributeTargets.Delegate |
                AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
[NoCodeCoverage]
public sealed class CanBeNullAttribute : Attribute
{
}

Deux classes vides héritant de Attribute. Comment sont-ils utilisés? Devez-vous rechercher la documentation xml et savoir qu'elle existe? Parce que j'ai essayé à la fois de faire ma propre copie de l'attribut et d'utiliser la version de Lokad, mais quand j'ai essayé d'envoyer un null directement, je n'ai reçu aucun message. Ni de ReSharper ni de VS. Ce à quoi je m'attendais en fait. Mais comment sont-ils utilisés? Puis-je faire en sorte que VS génère des avertissements pour moi si j'essaie d'envoyer quelque chose de nul là-dedans? Ou est-il simplement utilisé dans une sorte de cadre de test? Ou?

40
Svish

A moyen terme, les "contrats de code" (en 4.0) seront une meilleure réponse à cela. Ils sont maintenant disponibles (avec académique ou commercial licences), mais seront plus intégrés dans VS2010. Cela peut fournir à la fois une analyse statique et un support d'exécution.

(modifier) ​​exemple:

Contract.RequiresAlways( x != null );

Aussi simple que cela ... le moteur de contrats de code fonctionne au niveau IL, il peut donc analyser cela et lancer des avertissements/erreurs lors de l'appel du code lors de la construction ou lors de l'exécution. Pour une compatibilité ascendante, si vous avez un code de validation existant, vous pouvez simplement lui dire où se termine le contrôle d'intégrité, et il fera le reste:

if ( x == null ) throw new ArgumentNullException("x");
Contract.EndContractBlock();
46
Marc Gravell

Cela peut être fait soit avec AOP , par lequel un avis vérifie au moment de l'exécution si un paramètre de méthode est nul et si les valeurs nulles sont autorisées. Voir PostSharp et Spring.NET pour AOP.

Quant à ReSharper, voir Framework annoté :

Nous avons analysé une grande partie de la bibliothèque de classes .NET Framework, ainsi que NUnit Framework, et l'avons annotée via des fichiers XML externes, en utilisant un ensemble d'attributs personnalisés de l'espace de noms JetBrains.Annotations, en particulier:

  • StringFormatMethodAttribute (pour les méthodes qui prennent des chaînes de format comme paramètres)
  • InvokerParameterNameAttribute (pour les méthodes avec des arguments littéraux de chaîne qui doivent correspondre à l'un des paramètres de l'appelant)
  • AssertionMethodAttribute (pour les méthodes d'assertion)
  • AssertionConditionAttribute (pour les paramètres de condition des méthodes d'assertion)
  • TerminatesProgramAttribute (pour les méthodes qui mettent fin au flux de contrôle)
  • CanBeNullAttribute (pour les valeurs qui peuvent être nulles)
  • NotNullAttribute (pour les valeurs qui ne peuvent pas être nulles)
19
Anton Gogolev

Ces annotations sont destinées à ReSharper et sont copiées à partir de l'espace de noms JetBrains.Annotations. Un framework peut les placer dans leur propre espace de noms, cependant, ReSharper ne récupérera PAS ces annotations automatiquement - vous devez dire à ReSharper d'utiliser l'espace de noms personnalisé dans la boîte de dialogue des options. Une fois que vous avez sélectionné le nouvel espace de noms, l'analyse de ReSharper récupérera les attributs et vous donnera des faits saillants et des avertissements.

8
citizenmatt

Comme indiqué par Anton Gogolev , les attributs peuvent être créés à l'aide de PostSharp (notez que CodeContract utilise des appels de méthode statique à l'intérieur du corps de la méthode)

MISE À JOUR février 2013: la nouvelle version 3.0 de PostSharp (actuellement en version bêta) prendra en charge Validation des paramètres, des champs et des propriétés

1) Article validate-parameters-using-attributes a implémentation de

classe publique NotEmpty: ParameterAttribute

classe publique NotNull: ParameterAttribute

[AttributeUsage (AttributeTargets.Parameter)]

classe abstraite publique ParameterAttribute: Attribut

{

public abstract void CheckParameter(ParameterInfo parameter, object value); 

}

Il fallait également un attribut de méthode avec un aspect de limite de méthode pour traiter les attributs de paramètre.

2) Dans le commentaire de l'article, il y a des liens vers implémentation très similaire pour NonNull/NonEmpty

[return: NonNull] public SomeObject SomeMethod ([NonNull] AnotherObject param1)

Le code source se trouve dans google code Torch/DesignByContract

3) un autre exemple plus compliqué est décrit dans http://badecho.com/2011/11/validating-method-parameters-with-postsharp/

3
Michael Freidgeim