IList / IEnumerable的奇怪Linq行为

时间:2010-05-06 22:36:36

标签: c# .net linq

我有以下代码:

    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
}

基本上,NonPromoItems(ChildProducts - PromoItems)NonGiftItems(NonPromoItems - GiftItems)

然而当:

ChildProducts = IEnumerable<IProductViewModel>[6] PromoItems = IEnumerable<IProductViewModel>[1]其中,项目与ChildProducts中的1项匹配 GiftItems = IEnumerable<IProductViewModel>[0]

我的结果是

NonPromoItems = IEnumerable<IProductViewModel>[5] 这是正确的 NonGiftItems = IEnumerable<IProductViewModel>[4] 这是不正确的

当给出一个要删除的空列表时,某个Except(...)正在删除一个项目。

任何想法?

1 个答案:

答案 0 :(得分:3)

删除的项目是否与列表中的另一项重复?如果是这样,这是Except方法调用的标准行为:

除了&lt; T&gt;有点棘手的是,它不是像你期望的那样返回差异,而是返回 set 的差异。数学集不包含重复项(例如HashSet)。

这是我的意思的一个例子:

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

您可以在我描述问题的this CodeProject thread上阅读更多内容。

要在保留重复项的同时获得“类似”功能,您可以编写以下行:

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