Подтвердить что ты не робот

Как использовать IEqualityComparer

У меня есть несколько колоколов в моей базе данных с таким же числом. Я хочу получить все из них без дублирования. Затем я создаю класс сравнения для выполнения этой работы, но выполнение функции делает большую задержку от функции без четкой, от 0,6 с до 3,2 с!

Я делаю это правильно или мне нужно использовать другой метод?

       reg.AddRange((from a in this.dataContext.reglements
                     join b in this.dataContext.Clients on a.Id_client equals b.Id
                     where a.date_v <= datefin && a.date_v >= datedeb
                     where a.Id_client == b.Id
                     orderby a.date_v descending 
                     select new Class_reglement
                     {
                         nom = b.Nom,
                         code = b.code,
                         Numf = a.Numf,
                     }).AsEnumerable().Distinct(new Compare()).ToList());


    class Compare : IEqualityComparer<Class_reglement>
    {
        public bool Equals(Class_reglement x, Class_reglement y)
        {
            if (x.Numf == y.Numf)
            {
                return true;
            }
            else { return false; }
        }
        public int GetHashCode(Class_reglement codeh)
        {
            return 0;
        }

    }
4b9b3361

Ответ 1

Неудивительно, учитывая вашу реализацию GetHashCode, которая всегда возвращает одно и то же значение. Distinct полагается на хорошую хеш-функцию для эффективной работы.

При реализации интерфейсов классов вам нужно сначала прочитать документацию, иначе вы не знаете, какой контракт вы предполагаете для реализации. 1

В вашем коде решение должно пересылать GetHashCode в Class_reglement.Numf.GetHashCode и соответствующим образом реализовывать его.

Кроме того, ваш метод Equals заполнен ненужным кодом. Его можно было бы переписать следующим образом (та же семантика, 1/4 кода, более читаемая):

public bool Equals(Class_reglement x, Class_reglement y)
{
    return x.Numf == y.Numf;
}

Кроме того, вызов ToList не нужен и занимает много времени: AddRange принимает любое IEnumerable, поэтому преобразование в List не требуется. AsEnumerable также избыточен здесь, так как обработка результата в AddRange все равно приведет к этому.


1 Реализация кода, не зная, что он на самом деле делает, называется культовое программирование груза. Это удивительно распространенная практика. Это принципиально не работает.

Ответ 2

Попробуйте этот код:

public class GenericCompare<T> : IEqualityComparer<T> where T : class
{
    private Func<T, object> _expr { get; set; }
    public GenericCompare(Func<T, object> expr)
    {
        this._expr = expr;
    }
    public bool Equals(T x, T y)
    {
        var first = _expr.Invoke(x);
        var sec = _expr.Invoke(y);
        if (first != null && first.Equals(sec))
            return true;
        else
            return false;
    }
    public int GetHashCode(T obj)
    {
        return obj.GetHashCode();
    }
}

Пример его использования:

collection = collection
    .Except(ExistedDataEles, new GenericCompare<DataEle>(x=>x.Id))
    .ToList(); 

Ответ 3

Включение вашего класса сравнения (или, более конкретно, вызов AsEnumerable, который вам нужно использовать для его работы) означает, что логика сортировки переходила от базы данных к клиенту базы данных (ваше приложение). Это означало, что вашему клиенту теперь нужно получить и обработать большее количество записей, что всегда будет менее эффективным, если вы выполняете поиск в базе данных, где могут использоваться соответствующие индексы.

Вы должны попытаться разработать предложение where, которое удовлетворяет вашим требованиям вместо этого, см. Использование IEqualityComparer с LINQ to Entities За исключением предложения для более подробной информации.

Ответ 4

Просто код с реализацией GetHashCode и NULL проверки:

public class Class_reglementComparer : IEqualityComparer<Class_reglement>
{
    public bool Equals(Class_reglement x, Class_reglement y)
    {
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;

        return x.Numf == y.Numf;
    }

    public int GetHashCode(Class_reglement product)
    {
        //Check whether the object is null 
        if (Object.ReferenceEquals(product, null)) return 0;

        //Get hash code for the Numf field if it is not null. 
        int hashNumf = product.hashNumf == null ? 0 : product.hashNumf.GetHashCode();

        return hashNumf;
    }
}

Пример: список Class_reglement отличается Numf

List<Class_reglement> items = items.Distinct(new Class_reglementComparer());