Получить отличные значения списка

У меня есть приложение С#, в котором я хотел бы получить от List объектов Проект, другой Список, который содержит отдельные объекты.

Я попробовал это

 List<Project> model = notre_admin.Get_List_Project_By_Expert(u.Id_user);
 if (model != null) model = model.Distinct().ToList();

Модель списка по-прежнему содержит 4 идентичных объекта Project.

В чем причина этого? Как я могу это исправить?

Ответ 1

Здесь вам нужно определить "идентичный". Я предполагаю, что вы имеете в виду "иметь одно и то же содержимое", но не определение по умолчанию для классов: определение по умолчанию "это один и тот же экземпляр".

Если вы хотите, чтобы "идентичный" означал "иметь одно и то же содержимое", у вас есть два варианта:

  • напишите пользовательский сопоставитель (IEqualityComparer<Project>) и поставьте его как параметр Distinct
  • переопределить Equals и GetHashCode на Project

Существуют также настраиваемые методы, такие как DistinctBy, где доступно множество мест, что полезно, если идентификация может быть определена одним свойством (Id, как правило), но не в BCL. Но, например:

if (model != null) model = model.DistinctBy(x => x.Id).ToList();

С, например:

public static IEnumerable<TItem>
    DistinctBy<TItem, TValue>(this IEnumerable<TItem> items,
    Func<TItem, TValue> selector)
{
    var uniques = new HashSet<TValue>();
    foreach(var item in items)
    {
        if(uniques.Add(selector(item))) yield return item;
    }
}

Ответ 2

var newList = 
(
from x in model
select new {Id_user= x.Id_user}
).Distinct();

или вы можете написать вот так

var list1 = model.DistinctBy(x=> x.Id_user);

Ответ 3

Как вы определяете идентичность? Вы должны переопределить Equals в Project с этим определением (если вы переопределите Equals также переопределите GetHashCode). Например:

public class Project
{
    public int ProjectID { get; set; }

    public override bool Equals(object obj)
    {
        var p2 = obj as Project;
        if (p2 == null) return false;
        return this.ProjectID == m2.ProjectID;
    }

    public override int GetHashCode()
    {
        return ProjectID;
    }
}

В противном случае вы просто проверяете ссылочное равенство.

Ответ 4

Ссылка на объект не равна. Если вы хотите иметь возможность сделать это на самом объекте, а не просто на свойстве, вам нужно реализовать IEqualityComparer или IEquatable <T> .

Ответ 5

Проверьте этот пример: вам нужно использовать либо компаратор, либо переопределить Equals()

class Program
{
    static void Main( string[] args )
    {
        List<Item> items = new List<Item>();
        items.Add( new Item( "A" ) );
        items.Add( new Item( "A" ) );
        items.Add( new Item( "B" ) );
        items.Add( new Item( "C" ) );

        items = items.Distinct().ToList();
    }
}

public class Item
{
    string Name { get; set; }
    public Item( string name )
    {
        Name = name;
    }

    public override bool Equals( object obj )
    {
        return Name.Equals((obj as Item).Name);
    }
    public override int GetHashCode()
    {
        return Name.GetHashCode();
    }
}

Ответ 6

Здесь ответ в основном тот же вопрос, который поможет.

Пояснение:

Метод Distinct() проверяет ссылочное равенство для ссылочных типов. Это означает, что он ищет буквально тот же объект, который дублируется, а не разные объекты, которые содержат одинаковые значения.

Кредиты для @Rex M.

Ответ 7

Не проще использовать один из подходов, показанный ниже:)? Вы можете просто сгруппировать объекты своего домена с помощью некоторого ключа и выбрать FirstOrDefault, как показано ниже.

Более интересным вариантом является создание некоторого адаптера Comparer, который принимает объект домена и создает другой объект, который Comparer может использовать/работать с ним. На основе сравнения вы можете создавать свои пользовательские расширения linq, как в примере ниже. Надеюсь, это поможет:)

[TestMethod]
    public void CustomDistinctTest()
    {
        // Generate some sample of domain objects
        var listOfDomainObjects = Enumerable
                                    .Range(10, 10)
                                    .SelectMany(x => 
                                        Enumerable
                                        .Range(15, 10)
                                        .Select(y => new SomeClass { SomeText = x.ToString(), SomeInt = x + y }))
                                    .ToList();

        var uniqueStringsByUsingGroupBy = listOfDomainObjects
                                        .GroupBy(x => x.SomeText)
                                        .Select(x => x.FirstOrDefault())
                                        .ToList();

        var uniqueStringsByCustomExtension = listOfDomainObjects.DistinctBy(x => x.SomeText).ToList();
        var uniqueIntsByCustomExtension = listOfDomainObjects.DistinctBy(x => x.SomeInt).ToList();

        var uniqueStrings = listOfDomainObjects
                                .Distinct(new EqualityComparerAdapter<SomeClass, string>(x => x.SomeText))
                                .OrderBy(x=>x.SomeText)
                                .ToList();

        var uniqueInts = listOfDomainObjects
                                .Distinct(new EqualityComparerAdapter<SomeClass, int>(x => x.SomeInt))
                                .OrderBy(x => x.SomeInt)
                                .ToList();
    }

Пользовательский адаптер-адаптер:

public class EqualityComparerAdapter<T, V> : EqualityComparer<T>
    where V : IEquatable<V>
{
    private Func<T, V> _valueAdapter;

    public EqualityComparerAdapter(Func<T, V> valueAdapter)
    {
        _valueAdapter = valueAdapter;
    }

    public override bool Equals(T x, T y)
    {
        return _valueAdapter(x).Equals(_valueAdapter(y));
    }

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

Пользовательское расширение linq (определение метода расширения DistinctBy):

// Embedd this class in some specific custom namespace
public static class DistByExt
{
    public static IEnumerable<T> DistinctBy<T,V>(this IEnumerable<T> enumerator,Func<T,V> valueAdapter)
        where V : IEquatable<V>
    {
        return enumerator.Distinct(new EqualityComparerAdapter<T, V>(valueAdapter));
    }
}

Определение объекта домена, используемого в тестовом примере:

public class SomeClass
{
    public string SomeText { get; set; }
    public int SomeInt { get; set; }

}

Ответ 8

List<ViewClReceive> passData = (List<ViewClReceive>)TempData["passData_Select_BankName_List"];
    passData = passData?.DistinctBy(b=>b.BankNm).ToList();

Он будет работать...