12
votes

Testez les valeurs null en C #

Si je fais quelque chose comme: xxx

est un bon moyen de vérifier les valeurs null sans utiliser l'essai / prise? C'est juste que je ne me soucie pas si la valeur "Col1" est nulle ou si "Col1" n'existait pas, ou s'il n'y avait pas de rangées retournées, ou si la table n'existe pas! < p> Peut-être que je devrais m'occuper? :) Peut-être essayer / attraper est la meilleure façon d'aborder cela, mais je me demandais simplement s'il y avait une autre façon de le faire?

Merci!


3 commentaires

Tout d'abord, ne faites pas un générique . C'est une pratique horrible. Attrapez les erreurs que vous recherchez.


D'accord. Il a été juste lancé dans un exemple, mais c'est une sorte de même point - "N'utilisez pas la manipulation des erreurs pour attraper des choses qui ne sont pas vraiment des erreurs". Je cherchais peut-être peut-être que des techniques / mots-clés C # sont liées à ce problème.


Le peut-être monade semble être une bonne chose ici. codeproject.com/kb/cs/maybemonads.aspx


14 Réponses :


-1
votes

Vous recherchez DBNULL.Value E.G.

if (ds.Tables[0].Rows[0]["col1"] != DBNull.Value)


1 commentaires

Problèmes de: NULL DataSet, pas de tables, pas de lignes, etc.



7
votes

Il est un peu étrange de ne pas se soucier de la table ou de la colonne.

C'est une pratique beaucoup plus normale à attendre Tableau [0] .rows.count == 0 par exemple.

Et la meilleure façon de vérifier que les valeurs NULL sont avec si (...) ... sinon ... .
Le pire moyen est d'attendre des exceptions (de quelque manière que ce soit).


10 commentaires

Je suppose. C'est juste que même après avoir écrit tout le code indiquant "s'il y a un jeu de données et s'il y a une table et s'il y a une ligne et s'il y a une colonne", le résultat final est toujours vraiment intéressé Pour obtenir une valeur ou non! Il existe sûrement un moyen d'augmenter la lisibilité du code ici?


«Augmentez la lisibilité du code ici» - une meilleure conception, et peut-être moins de données de données. Vos requêtes doivent toujours produire un type (un peu) défini, de sorte que les tables et les colonnes manquantes peuvent être évitées.


C'était juste un exemple. Nous avons tous rencontré la situation (pas nécessairement avec des jeux de données) où vous avez des objets imbriqués et que vous devez dire si obj! = Null && obj.obj1! = Null && obj.obj1.obj2! = Null puis obtenir obj.obj1. obj2.value. Droite?


@JQWha, il n'y a pas de raccourci. Il a souvent été demandé à un opérateur de la forme ?. où vous pouviez dire a? .B , et si a a été null, ceci Ne lanceriez pas, la sortie serait définie comme null ou peut-être la valeur par défaut du type de B . Mais cela ne fait actuellement pas partie de la langue ni je suis conscient si cela est même une possibilité pour une future version.


Oui ça arrive. Mais quand il est fréquent ou plus de 2 niveaux de profondeur, je commence à regarder en arrière au design.


@Anthony - Je pensais alors :(. Merci.


@Henk - Je sais ce que vous impliquez, mais je n'ai jamais acheté le commentaire de "C'est ton design". Il est trop académique d'assumer la pureté = la simplicité et la poursuite des conceptions académiquement pures conduit souvent à une complexité considérablement accrue.


"Complexité très accrue" - comme dans @redfilters réponse? Mais notez que j'ai essayé d'admettre les nuances de gris.


Il existe souvent des situations dans lesquelles il est complètement valable de dire "quelque part dans cette hiérarchie profonde d'objets, quelque chose peut ne pas être présent, ce qui signifie que tous les enfants ne seront pas présents, et ce n'est pas important, pourquoi ils ne sont pas présents, ils Ce n'est pas parce que c'est un état de choses logiquement cohérent ». Je cherche juste le soutien dans la langue pour quelque chose qui se passe tout le temps. Nous le prenons pour acquis que vous pouvez ajouter 2 à -3 et obtenir -1, sans vérifier que des chiffres sont inférieurs à 0, non?


Si vous parlez de collections, Linq gère cela assez élégamment. Dans d'autres contextes, vous avez généralement besoin d'un si par niveau, mais pas nécessairement dans une seule déclaration. La programmation structurée (méthodes d'empilement) fonctionne toujours.



1
votes

Vous pourrez peut-être utiliser le ternaire nullable '??', mais je pense que la null qui est renvoyée est un "dbnull" et non "null".

L'exemple serait ... P >

string somevalue = ds.Tables[0].Rows[0]["col1"] ?? "";


1 commentaires

Vous avez raison de ne pas être suffisant ici. Et c'est l'opérateur de coalescence nul, pas un "terary" ou ternaire. Celui que tout le monde appelle le ternaire est l'opérateur conditionnel, avec la forme a? B: C .



0
votes

Vous devrez les vérifier tous pour NULL (ou d'autres types NULL) un par un, commençant au sommet (qui est le jeu de données)

si (DS! = null) Si (table! = null) ...

Vous pouvez le faire sans, mais votre code sera beaucoup plus susceptible aux erreurs.


1 commentaires

Oui mais vois mon commentaire à Henk, ci-dessus.



4
votes
if (ds == null
    || ds.Tables == null 
    || ds.Tables.Count == 0
    || ds.Tables[0].Rows == null 
    || ds.Tables[0].Rows.Count == 0
    || ds.Tables[0].Rows[0].IsNull("col1")
)
//there is no data...
...

2 commentaires

Peut-être commencer par si (world == null || ...


MDR. Ils ont vraiment besoin de construire quelque chose de récursif dans la langue.



0
votes

d'un point de vue de maintenance, ce que vous faites est très souhaitable.

Sinon, vous devez: vérifier si DS est NULL, vérifiez s'il y a des tables dans l'ensemble de données, vérifiez s'il y a des lignes dans la table, vérifiez si la colonne existe, vérifiez pour voir S'il y a des données dans la colonne.

Il élimine certainement beaucoup de code fastidieux.


0 commentaires

3
votes

Si vous voulez vous assurer que votre code n'échoue pas, vous devrez réellement vérifier tous les éléments de la hiérarchie, par exemple: xxx


0 commentaires

1
votes

Certaines vérifications:

string somevalue = String.Empty;
if (ds.Tables.Count > 0)
        {
            System.Data.DataTable dt = ds.Tables[0];
            if (dt.Rows.Count > 0)
            {
                System.Data.DataRow dr = dt.Rows[0];
                if (dt.Columns.Count>0 && dt.Columns.Contains("col1"))
                {
                   somevalue = dr["col1"].ToString();
                }
            }
        }


0 commentaires

0
votes

Ce que j'ai utilisé dans le passé est une petite wrapper de tests nuls qui renvoient une valeur par défaut. Par exemple: xxx

utilisé: xxx


1 commentaires

Comme d'autres ont dit que la chaîne, quelqueévalue doit être exécutée après avoir été sûrement des lignes existantes en premier.



0
votes

Je pense que vous devriez faire explicit que vous ne vous souciez pas de toutes ces choses, ce qui signifie que vous devez gérer chaque cas explicitement: xxx

c'est plus de code, mais pour moi, il communique le Intention plus clairement.


2 commentaires

Mais «l'intention» est la récupération d'une valeur. Je ne pense pas que nous devrions préciser toutes les choses que nous ne nous soucions pas. Je ne suis pas un pirate informatique ou quoi que ce soit, mais il y a un équilibre à frapper, je pense?


Je dirais que l'intention est d'obtenir la valeur tout en manipulant un tas de cas spéciaux, "spécial" étant le mot clé ici. Ne pas se soucier de ces choses est important ici car ce n'est pas habituel. Bien sûr, vous pourriez (et devrait probablement) mettre cela dans une méthode et la réutiliser, rendre les frais généraux du code supplémentaire moins pertinent.



0
votes

Je pense peut être monad est la meilleure chose pour cette situation (l'échantillon est de la source):

ds.With(x=>Tables[0]).With(x=>x.Rows).With(x=>x[0])...


1 commentaires

Pouvez-vous élaborer comment vous avez fait fonctionner avec des jeux de données? Essayé de faire quelque chose de similaire, mais ça se brise et me donne un "..". => E.Tables [0]). Avec (E => E.Rows) .avec (E => E [0]). Avec (E => E ["Description"]). Tostring ();



0
votes

Si vous envoyez vraiment des ensembles de données, des index et des noms non validés aléatoires, vous pouvez faire une méthode d'assistance comme celle-ci: xxx

puis utilisez quelque chose comme getdataseSetValue ( ds, 0, 0, "col1") .


2 commentaires

Quelle est votre alternative suggérée qui couvrira toutes les éventualités de l'accès requis sur les données?


@JQWha Modifiez la méthode à ce que vous envisageriez toutes les éventualités, puis appelez-la, j'ai essayé d'inclure toutes les éventualités que vous avez mentionnées, mais vous pouvez utiliser l'idée pour la mettre en œuvre.



2
votes
DataSet ds = GetMyDataset();

string somevalue = ds != null ? ds.Tables[0].Rows[0]["col1"].ToString() : null;

0 commentaires

0
votes

Je déteste avoir à traiter d'une couche d'accès aux données qui ne me garantit pas un ensemble standard de résultats: une requête SQL donnée ou une procédure stockée doit être toujours renvoyer le même schéma de jeu de résultats. Traiter avec des ensembles vides (AKA Datables) est facile. Traiter avec des références d'objet manquantes arbitraires ... pas tellement.

La bonne réponse consiste à corriger votre code d'accès aux données afin qu'il renvoie un schéma cohérent.

omettant que, si je dois gérer le code Comme ça, je fais quelque chose comme ceci: xxx

Il est facile de déboguer soit dans le débogueur, soit via la journalisation. Donnez l'ensemble de 5 valeurs, vous pouvez facilement voir ce qui était présent et ce qui manquait. Il est facile de voir quelle hypothèse (contrainte?) A été violée.


0 commentaires