1
votes

Exception de référence nulle après vérification de null (la vérification de null ne fonctionne pas)

Jetez un œil à ce code:

var categories = tokens.SelectMany(x => x.Categories);

if (categories != null)
{
    if (categories.Contains("interp")) //null ref exception
    {
        return null;
    }
}

J'obtiens une exception de référence nulle quand j'essaye de trouver la chaîne "interp" dans les catégories. Il semble donc que "categories! = Null" ne fonctionne pas.

J'ai trouvé quelques suggestions (ici Comment pour vérifier si IEnumerable est nul ou vide? ) mais ils impliquent d'utiliser .Any (). Mais cela ne rend l'exception que plus tôt (en utilisant .Any ()). Même? .Any () lève l'exception.

Des idées?


9 commentaires

Vérifiez tokens! = Null si tokens n'est pas null , SelectMany ne renverra jamais null mais énumérable vide


Peut-être qu'un élément de tokens est null . x.Categories lèverait alors une exception lorsque vous appelez Contains .


Les vérifications nulles fonctionnent. Si vous obtenez un NRE, cela signifie que quelque chose d'autre a échoué. Publiez le texte d'exception complet , y compris la pile d'appels. C'est peut-être une ligne différente qui a jeté, ou Enumerable.Contains a jeté parce que categories est vide. Ou peut-être que x.Categories contenait en fait des entrées null qui se sont retrouvées dans la variable categories .


categories! = null vérifie les catégories énumérables, pas son contenu. S'il y a une chance que x.Categories contienne des valeurs nulles, vous devez inclure un Where (category => category! = Null)


Quel type est votre selectmany de retour?


@DmitryBychenko Si tokens == null , SelectMany doit cependant lancer une ArgumentNullException . Est-ce que je manque quelque chose?


Ce serait génial si vous pouviez fournir un exemple reproductible minimal . Quel est le type de catégories ?


Exécutez cette ligne de code if (categories.Contains ("interp")) . Lorsque vous cliquez dessus, veuillez accéder à la Fenêtre Exécution et saisir les ? Catégories . Qu'est-ce qui est retourné? Et pour ? Categories.Count () ? Qu'en est-il des ? Categories.GetType () ?


@ Peter82 cette question doit être fermée soit comme peu claire, soit comme un double de Qu'est-ce qu'une NullReferenceException et comment la corriger? . Il n'y a aucun moyen de reproduire ce que la question prétend - un Enumerable emtpy ne lance pas. La comparaison avec null n'est pas cassée, des millions de développeurs l'auraient remarqué si c'était le cas. Vous devez publier un exemple reproductible et le texte de l'exception complet , y compris la pile d'appels. Vous pouvez l'obtenir facilement avec une simple Exception.ToString () .


4 Réponses :


3
votes

Lorsque vous travaillez avec des collections et IEnumerable , évitez d'utiliser null ; si vous n'avez rien à renvoyer, renvoyez une collection vide (et non null ).

Dans votre cas particulier, SelectMany ne renverra jamais null , mais collection vide, c'est pourquoi la vérification de categories! = null est inutile , et vous devez vérifier jetons à la place

// if tokens is null change it for an empty collection
tokens = tokens ?? new MyToken[0];

...

if (tokens 
      .Where(x => x != null && x.Categories != null)
      .SelectMany(x => x.Categories)
      .Contains("interp"))
    return null;

Cependant, la vérification constante de null rend le code illisible , c'est pourquoi essayez de vérifier null once:

if (null != tokens)
  // Where(x => x != null) - to be on the safe side if x == null or x.Categories == null
  if (tokens
       .Where(x => x != null && x.Categories != null)
       .SelectMany(x => x.Categories)
       .Contains("interp"))
    return null;


0 commentaires

0
votes

var categories = tokens.SelectMany (x => x.Categories) .ToList ();

ajoutez .ToList () et vous devriez en savoir plus sur l'emplacement de l'erreur avec ces informations que nous avons dans le post, nous ne pouvons que deviner


1 commentaires

ToList (); - essayez d'éviter la matérialisation lorsque vous n'avez pas à le faire; imagerie que tokens.SelectMany renvoie généralement millions d'éléments (quelle énorme liste que nous créons pour rien puisque Contains ne le veut pas)



4
votes

Ce code lancera un NRE dans categories.Contains uniquement si la propriété Categories est nulle.

Le code suivant lancera:

class Token
{
    string[] _categories=new string[0];
    public string[] Categories{
        get => _categories;
        set => _categories = value??new string[0];
    }

}

Mais il en irait de même

var categories = tokens.Where(x=>x.Categories!=null).SelectMany(x => x.Categories);

La chose qui lance réellement est le itérateur dans SelectMany , pas ToArray () ou Contains . La trace de pile pour cette exception est:

at System.Linq.Enumerable.<SelectManyIterator>d__17`2.MoveNext()
at System.Linq.Enumerable.Contains[TSource](IEnumerable`1 source, TSource value, IEqualityComparer`1 comparer)
at UserQuery.Main()

SelectMany essaiera d'itérer sur chaque entrée Categories , trouver que le La propriété est en fait nulle et rejetée.

La solution rapide consiste à ajouter un Where avant SelectMany pour éliminer les catégories nulles:

tokens.SelectMany(x => x.Categories).ToArray();

La vraie solution est de s'assurer que Catégories n'est jamais vide - il devrait être initialisé à un tableau, une liste vide, quoi que ce soit lors de la construction. Lorsqu'il est réaffecté, il ne doit jamais être défini sur null.

Cet exemple définit le champ _categories sur nouvelle chaîne [0] même si un appelant passe null aux catégories

class Token
{
    public string[] Categories{get;set;}
}

var tokens=new []{new Token()};
var categories = tokens.SelectMany(x => x.Categories);
if (categories != null)
{
    if (categories.Contains("interp")) 
    {
        Console.WriteLine("Found");
    }
}

Avec cela, Where (x => x.Categories! = null) n'est plus nécessaire


1 commentaires

C'est la seule réponse qui semble avoir raison. Les jetons ne peuvent jamais être nuls si SelectMany ne lève pas d'exception. Upvote!



0
votes

Peut utiliser la clause where et en faire une liste, puis vérifier simplement s'il y a un élément dans la liste

 var categories = list.Where(x => x.Categories.Contains("interp")).ToList();
 if (categories.Count() == 0)
  {
     return null;

   }


0 commentaires