2010-05-06 6 views
0

J'ai le code suivant:comportement étrange Linq avec IList/IEnumerable

public IList<IProductViewModel> ChildProducts { get; set; } 
    public IList<IProductViewModel> GiftItems { get; set; } 
    public IList<IProductViewModel> PromoItems { get; set; } 

    public IList<IProductViewModel> NonGiftItems 
    { 
     get 
     { 
      return NonPromoItems.Except(GiftItems, new ProductViewModelComparer()).ToList(); 
     } 
    } 

    public IList<IProductViewModel> NonPromoItems 
    { 
     get 
     { 
      return ChildProducts.Where(p => !p.IsPromotion).ToList(); 
     } 
    } 

ProductViewModelComparer:

public class ProductViewModelComparer : IEqualityComparer<IProductViewModel> 
{ 

    #region IEqualityComparer<IProductViewModel> Members 

    public bool Equals(IProductViewModel x, IProductViewModel y) 
    { 
     if (Object.ReferenceEquals(x, y)) 
      return true; 

     if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) 
      return false; 

     return String.Equals(x.ProductId, y.ProductId); 
    } 

    public int GetHashCode(IProductViewModel obj) 
    { 
     return obj.ProductId.GetHashCode(); 
    } 

    #endregion 
} 

Donc, fondamentalement, NonPromoItems est (ChildProducts - PromoItems) et NonGiftItems est (NonPromoItems - GiftItems)

Toutefois, lorsque :

ChildProducts = IEnumerable<IProductViewModel>[6] PromoItems = IEnumerable<IProductViewModel>[1] où l'article correspond à 1 pièce ChildProducts GiftItems = IEnumerable<IProductViewModel>[0]

Mon résultat est

NonPromoItems = IEnumerable<IProductViewModel>[5]Ceci est correct NonGiftItems = IEnumerable<IProductViewModel>[4]Ceci est incorrect

D'une manière ou d'une autre Except(...) supprime un élément lorsqu'il reçoit une liste vide à soustraire.

Vous avez des idées?

+0

Peut-on voir le code comparateur? – Aaronaught

+0

Il y a le code, ne devrait pas importer puisqu'il compare 'NonPromoItems' à' GiftItems' et 'GiftItems' est vide ... – Aren

Répondre

3

L'élément supprimé est-il un doublon d'un autre élément de la liste? Si oui, ce comportement est standard pour la méthode Sauf appel:

L'exception <T> est un peu délicate dans la mesure au lieu de retourner la différence comme on pouvait s'y attendre, il retourne à la place du mis différence. Un ensemble mathématique ne contient pas de doublons (par exemple, HashSet).

Voici un exemple de ce que je veux dire:

int[] ints = { 3, 3, 3 }; 
var result = ints.Except(5); // result contains one element only: { 3 } 

Vous pouvez en savoir plus sur this CodeProject thread où je l'ai décrit le problème.

Pour obtenir « Sauf » fonctionnalité -comme tout en laissant les doublons, vous pouvez écrire la ligne suivante:

var ints = new [] { 3, 42, 3 }; 
var excluded = new [] { 42 }; 
var results = ints.Where(i => !excluded.Contains(i)); // returns { 3, 3 } 
+0

Oui, c'est une dupe, savoir s'il y a un moyen de faire la même opération linq mais pas supprimer entrées distinctes? – Aren

+0

Ouais, il y a. Je mettrai à jour mon message pour montrer un exemple. –