web-dev-qa-db-fra.com

Marquer les paramètres comme NON Nullable dans C # /. NET?

Existe-t-il un attribut simple ou un contrat de données que je peux attribuer à un paramètre de fonction qui empêche la transmission de null dans C # /. NET? Idéalement, cela vérifierait également au moment de la compilation pour vous assurer que le littéral null n'est utilisé nulle part pour lui et au lancement au moment de l'exécution ArgumentNullException.

Actuellement j'écris quelque chose comme ...

if (null == arg)
  throw new ArgumentNullException("arg");

... pour chaque argument que je m'attends à ne pas être null.

Sur la même note, existe-t-il un contraire à Nullable<> par lequel les éléments suivants échoueraient:

NonNullable<string> s = null; // throw some kind of exception
87
Neil C. Obremski

Malheureusement, il n'y a rien de disponible à la compilation.

J'ai un peu de solution hacky que j'ai posté récemment sur mon blog, qui utilise une nouvelle structure et des conversions.

Dans .NET 4.0 avec les trucs Contrats de code , la vie sera beaucoup plus agréable. Il serait tout de même assez agréable d'avoir une syntaxe de langage réelle et un support autour de la non-nullité, mais les contrats de code aideront beaucoup.

J'ai également une méthode d'extension dans MiscUtil appelée ThrowIfNull qui le rend un peu plus simple.

Un dernier point - une raison pour utiliser "if (null == arg)" au lieu de "if (arg == null)"? Je trouve ce dernier plus facile à lire, et le problème que l'ancien résout en C ne s'applique pas à C #.

66
Jon Skeet

Je sais que je suis incroyablement en retard à cette question, mais je pense que la réponse deviendra pertinente à mesure que la dernière itération majeure de C # se rapprochera de la sortie, puis sera publiée. Dans C # 8.0, un changement majeur se produira, C # supposera que les types tous ne sont pas considérés comme nuls.

Selon Mads Torgersen:

Le problème est que les références nulles sont tellement utiles. En C #, ils sont la valeur par défaut de chaque type de référence. Quelle serait la valeur par défaut? Quelle autre valeur aurait une variable, jusqu'à ce que vous puissiez décider quoi d'autre lui affecter? Avec quelle autre valeur pourrions-nous ouvrir un tableau de références fraîchement alloué, jusqu'à ce que vous ayez le temps de le remplir?

De plus, parfois null est une valeur sensible en soi. Parfois, vous voulez représenter le fait que, disons, un champ n'a pas de valeur. Que c'est ok de ne passer "rien" pour un paramètre. L'accent est mis sur parfois, cependant. Et là réside une autre partie du problème: les langages comme C # ne vous permettent pas d'exprimer si une valeur nulle ici est une bonne idée ou non.

La résolution présentée par Mads est donc:

  1. Nous pensons qu'il est plus courant de vouloir qu'une référence ne soit pas nulle. Les types de référence nullables seraient les plus rares (bien que nous n'ayons pas de bonnes données pour nous dire combien), ce sont donc ceux qui devraient nécessiter une nouvelle annotation.

  2. Le langage a déjà une notion de - et une syntaxe pour - les types de valeurs nullables. L'analogie entre les deux rendrait l'ajout de langue conceptuellement plus facile et linguistiquement plus simple.

  3. Il semble juste que vous ne deviez pas vous encombrer vous-même ou votre consommateur avec des valeurs nulles encombrantes à moins que vous n'ayez décidé activement de les vouloir. Les null, et non leur absence, devraient être la chose à laquelle vous devez explicitement adhérer.

Un exemple de la fonctionnalité souhaitée:

public class Person
{
     public string Name { get; set; } // Not Null
     public string? Address { get; set; } // May be Null
}

L'aperçu est disponible pour Visual Studio 2017, version 15.5.4+.

14
Greg

Je sais que c'est une TRÈS vieille question, mais celle-ci manquait ici:

Si vous utilisez ReSharper/Rider, vous pouvez utiliser le Annotated Framework .

Edit : Je viens de recevoir un -1 aléatoire pour cette réponse. C'est très bien. Sachez simplement que c'est encore valide, même si ce n'est plus l'approche recommandée pour les projets C # 8.0 + (pour comprendre pourquoi, voir réponse de Greg ).

14
rsenna

Découvrez les validateurs dans la bibliothèque d'entreprise. Vous pouvez faire quelque chose comme:

private MyType _someVariable = TenantType.None;
[NotNullValidator(MessageTemplate = "Some Variable can not be empty")]
public MyType SomeVariable {
    get {
        return _someVariable;
    }
    set {
        _someVariable = value;
    }
}

Puis dans votre code lorsque vous souhaitez le valider:

Microsoft.Practices.EnterpriseLibrary.Validation.Validator myValidator = ValidationFactory.CreateValidator<MyClass>();

ValidationResults vrInfo = InternalValidator.Validate(myObject);
9
NotMe

pas la plus jolie mais:

public static bool ContainsNullParameters(object[] methodParams)
{
     return (from o in methodParams where o == null).Count() > 0;
}

vous pourriez également être plus créatif dans la méthode ContainsNullParameters:

public static bool ContainsNullParameters(Dictionary<string, object> methodParams, out ArgumentNullException containsNullParameters)
       {
            var nullParams = from o in methodParams
                             where o.Value == null
                             select o;

            bool paramsNull = nullParams.Count() > 0;


            if (paramsNull)
            {
                StringBuilder sb = new StringBuilder();
                foreach (var param in nullParams)
                    sb.Append(param.Key + " is null. ");

                containsNullParameters = new ArgumentNullException(sb.ToString());
            }
            else
                containsNullParameters = null;

            return paramsNull;
        }

bien sûr, vous pouvez utiliser un intercepteur ou une réflexion, mais ceux-ci sont faciles à suivre/à utiliser avec peu de frais généraux

0
Jeff Grizzle