C#中一个类的列表与另一个类的列表有什么区别?

3

我遇到了一个问题,无法理解在c#中两个列表的区别。

如何获取它们之间的差异?我尝试过使用Except方法,但是没有得到我想要的结果。

例如:这些产品是账单的一部分。

class Product {
   public int id_prod;
   public int quantity;
   public float price;
}

Product prd1 = new Product(){1,2,34};
Product prd2 = new Product(){2,5,20};
Product prd3 = new Product(){3,6,14};
Product prd4 = new Product(){4,9,8};
Product prd5 = new Product(){5,12,70};
Product prd1b = new Product(){1,60,34};


List<Product> oldLst = new List<Product>(){ prd1,prd2,prd3};
List<Product> newLst = new List<Product>(){ prd1b,prd2,prd4,prd5};

请注意,在旧prd1和新prd1之间数量可能会发生变化。
我的问题是当我使用var lstToDel = oldLst.Except(newLst);时,lstToDel被填充了oldLst,并没有产生差异。
期望的结果是:
lstToDel = new List<Product>(){prd1,prd3};

4
您的类没有覆盖EqualsGetHashCode方法,因此只有引用被比较。 - Tim Schmelter
如何设置equals来检查id和数量? - Biscuit
@Biscuit:恐怕我完全不理解那个评论。你提供的代码无法编译,而且你也没有清楚地描述问题,这真的没有帮助。我很想帮忙,但是你的问题目前太不清楚了。你是在说实际上你并没有为prd1调用new Product,而是改变了一个已存在对象的数量和价格吗? - Jon Skeet
1
请注意,如果您调用 prd1.quantity = 60;,则在 oldLstnewLst 中都会有对此对象的引用。因此,oldLst.First().quantitynewLst.First().quantity 都将等于 60。您确定这就是您想要的吗? - Ivan Gritsenko
1
确实,这感觉更像是对引用类型工作原理的理解不足,而不是LINQ的问题。 - Jon Skeet
显示剩余3条评论
3个回答

0

你应该在Product类中重写Equals方法,并定义比较Product的标准。或者定义你自己的

class MyComparer: IEqualityComparer<Product>
{
}

如果你看到实现,你应该注意它使用了Equals,因此创建你的比较器,当你调用Except时,你将得到所需的结果。
/// <typeparam name="T">The type of objects to compare.This type parameter is contravariant. That is, you can use either the type you specified or any type that is less derived. For more information about covariance and contravariance, see Covariance and Contravariance in Generics.</typeparam>
  [__DynamicallyInvokable]
  public interface IEqualityComparer<in T>
  {
    /// <summary>
    /// Determines whether the specified objects are equal.
    /// </summary>
    /// 
    /// <returns>
    /// true if the specified objects are equal; otherwise, false.
    /// </returns>
    /// <param name="x">The first object of type <paramref name="T"/> to compare.</param><param name="y">The second object of type <paramref name="T"/> to compare.</param>
    [__DynamicallyInvokable]
    bool Equals(T x, T y);

    /// <summary>
    /// Returns a hash code for the specified object.
    /// </summary>
    /// 
    /// <returns>
    /// A hash code for the specified object.
    /// </returns>
    /// <param name="obj">The <see cref="T:System.Object"/> for which a hash code is to be returned.</param><exception cref="T:System.ArgumentNullException">The type of <paramref name="obj"/> is a reference type and <paramref name="obj"/> is null.</exception>
    [__DynamicallyInvokable]
    int GetHashCode(T obj);
  }
}

这是 Except 实现

 [__DynamicallyInvokable]
    public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
    {
      if (first == null)
        throw Error.ArgumentNull("first");
      if (second == null)
        throw Error.ArgumentNull("second");
      else
        return Enumerable.ExceptIterator<TSource>(first, second, comparer);
    }

0

你也可以定义自己的通用扩展方法,像这样:

    public static IEnumerable<T> Except<T>(this IEnumerable<T> collection, IEnumerable<T> comparand, Func<T, object> comparer)
    {
        return collection.Except(comparand, new FuncComparer<T>(comparer));
    }

使用自定义的比较器:

public class FuncComparer<T> : IEqualityComparer<T>
{
    private readonly Func<T, object> _comparer;

    public FuncComparer(Func<T, object> comparer)
    {
        _comparer = comparer;
    }

    public bool Equals(T x, T y)
    {
        return _comparer(x) == _comparer(y);
    }

    public int GetHashCode(T obj)
    {
        return _comparer(obj).GetHashCode();
    }
}

然后你可以像这样使用它:

var lstToDel = oldLst.Except(newLst, x=>x.id_prod); // your comparer logic is on id_prod property

这将仅适用于简单的属性比较。对于更复杂的相等比较器,最好制作自己的自定义IEqualityComparer。


0

谢谢,这正是我所需要的。 - Biscuit
我尝试过了,但它仍然只返回一个项目。 - John Alexiou
你是如何实现比较器的? - Siderite Zackwehdex
我复制/粘贴了链接中声明第二个比较器的第一部分,并用我的数据(ID和数量代替名称和ID)进行了更改。然后我这样调用它:lstToDel = oldLst.Except(newLst, new ProductComparer()); - Biscuit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接