2009-11-30 7 views
6

J'utilise la déclaration ci-dessous avec l'intention d'obtenir tous les objets de la machine de la collection MachineList (type IEnumerable) qui ont un MachineStatus de i. La collection MachineList ne contient pas toujours les machines dont le statut est i.une collection vide quand Linq où ne retourne rien

À des moments où aucune machine n'a un MachineStatus de i Je voudrais retourner une collection vide. Mon appel à ActiveMachines (qui est utilisé en premier) fonctionne mais InactiveMachines ne fonctionne pas.

public IEnumerable<Machine> ActiveMachines 
{ 
    get 
    { 
     return Customer.MachineList 
      .Where(m => m.MachineStatus == "a"); 
    } 
} 

public IEnumerable<Machine> InactiveMachines 
{ 
    get 
    { 
     return Customer.MachineList 
      .Where(m => m.MachineStatus == "i"); 
    } 
} 

Modifier

Un examen plus poussé, il semble que toute énumération des MachineList entraînera énumérations suivants du MachineList jeter un exeception: Object reference not set to an instance of an object.

Par conséquent, peu importe si un appel est fait à ActiveMachines ou InactiveMachines comme son un problème avec la collection MachineList. Ceci est particulièrement troublant parce que je peux casser les appels à MachineList simplement en l'énumérant dans une montre avant qu'elle soit appelée dans le code. Au niveau le plus bas, MachineList implémente NHibernate.IQuery renvoyé comme IEnumerable. Qu'est-ce qui fait que MachineList perd son contenu après une énumération initiale?

+0

Non, rien spécial arrive à l'énumération; il serait intéressant de voir ce que "inactif" etc sont dans le débogueur. Je me demande aussi si (par exemple) 'MachineStatus' est une propriété de façade qui lance une exception - c'est-à-dire' chaîne publique MachineStatus {get {return someInnerField.Status;}} 'et' someInnerField' est 'null'. –

+0

Le vrai problème est que vous êtes en train d'énumérer un 'IEnumerable' plusieurs fois. Le contrat implicite que vous acceptez lorsque vous consommez «IEnumerable» est de ne l'énumérer qu'une seule fois! Donc, la vraie réponse n'est pas que votre collègue change son code pour permettre l'énumération multiple, mais que vous fassiez 'Customer.MachineList.ToList()' à un moment donné, puis que vous n'utilisiez la liste résultante qu'après (ou, obtenez un nouveau 'IEnumerable' à nouveau). Vous pouvez faire une évaluation paresseuse; vous pouvez le mettre en cache, mais ne l'enumez pas deux fois. Vous pouvez également exposer un 'IQueryable' et l'appeler plusieurs fois, aussi. – ErikE

Répondre

7

Where renvoie une séquence vide s'il n'y a pas de correspondance; c'est une séquence parfaitement valide (non nulle). La seule façon d'obtenir une valeur nulle est si vous appelez FirstOrDefault ou SingleOrDefault. Etes-vous sûr que le bug est là où vous pensez que c'est?

int?[] nums = { 1, 3, 5 }; 
var qry = nums.Where(i => i % 2 == 0); 
Console.WriteLine(qry == null); // false 
Console.WriteLine(qry.Count()); // 0 
var list = qry.ToList(); 
Console.WriteLine(list.Count); // 0 
var first = qry.FirstOrDefault(); 
Console.WriteLine(first == null); // true 
+0

C'est ce que je pensais. J'ai modifié ma question pour refléter une modification qui renvoie la même erreur. – ahsteele

+0

Ajout d'informations supplémentaires à ma question qui pourraient éclairer ce qui se passe. Cela dit, je pense que je pourrais être obligé d'ouvrir un nouveau sujet. – ahsteele

+0

L'erreur devait faire avec la façon dont MachineList était en cours de construction. J'avais consommé cette méthode d'un autre développeur et n'avait pas vérifié la façon dont il était construit. Merci de m'avoir indiqué la bonne direction en me demandant si j'étais sûr de regarder au bon endroit. – ahsteele

4

Par défaut, Enumerable.Where fait déjà retourner un vide IEnumerable<T>, non nul. Si vous voyez "Référence d'objet non définie sur une instance d'un objet". exceptions, il est plus probable que quelque chose d'autre est le problème.

MachineList est-elle nulle, peut-être? Si vous ne l'aviez pas créé, vous obtiendrez cette exception sur votre appel à .Where(...)

+0

Merci de m'avoir indiqué dans la bonne direction en demandant si j'étais sûr que je cherchais au bon endroit. – ahsteele

2

De plus, si vous souhaitez revenir explicitement une collection vide, cela peut aider ...

Enumerable.Empty<Machine>(); 
Questions connexes