2016-03-17 3 views
3

У меня возникли проблемы с получением разницы между двумя списками в C#.C# разница между списком классов

Как я могу получить разницу? Я попытался Исключить, но я не получил результат, которого я хотел.

, например: Эти продукты являются частью законопроекта

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

Ваш класс не переопределяет 'Equals' +' GetHashCode', поэтому сравниваются только ссылки. –

+0

Как установить равные для проверки идентификатора и количества? – Biscuit

+0

Ваш код будет намного понятнее, если вы не повторно использовали имя 'prd1' и выразили все это как [mcve]. На данный момент мы не знаем, каков фактический результат, или как вы это определяете. Я не думаю, что это на самом деле дубликат другого вопроса, поскольку на данный момент это похоже на то, что вы на самом деле * хотите * ссылочного равенства на данный момент, но без примера точно, что происходит, это трудно помочь. –

ответ

0

За исключением также принимает IEqualityComparer. Создайте один, чтобы определить, какие продукты «равны», что означает те же свойства. См. Больше: https://msdn.microsoft.com/en-us/library/bb336390.aspx

+0

Спасибо, что мне нужно. – Biscuit

+0

Я устал, и это подоконник возвращает один предмет. – ja72

+0

как вы реализовали компаратор? –

0

Вы должны переопределить Equals on Product и определить свои критерии для сравнения Продукта. Или определить ваш

class MyComparer: IEqualityComparer<Product> 
{ 
} 

если вы видите реализацию, то следует заметить, что использовать Equals, таким образом, создать свой Comparer, и вы получите результат вам нужно, когда вы называете исключением

/// <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); 
    } 
} 

Здесь есть Кроме реализации

[__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)); 
    } 

с настраиваемой 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.

Смежные вопросы