[c#] 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;
}
}
답변
귀하의 GetHashCode
구현은 항상 같은 값을 반환합니다. Distinct
내부적으로 해시 테이블을 구축하기 때문에 효율적인 작업을 위해 좋은 해시 함수에 의존 합니다 .
클래스의 인터페이스를 구현할 때 어떤 계약을 구현해야하는지 아는 문서 를 읽는 것이 중요합니다 . 1
코드에서이 솔루션은 전달하는 것입니다 GetHashCode
에 Class_reglement.Numf.GetHashCode
적절 거기를 구현합니다.
그 외에도 귀하의 Equals
방법은 불필요한 코드로 가득 차 있습니다. 다음과 같이 다시 작성할 수 있습니다 (동일한 의미, 코드의 ¼, 더 읽기 쉬움).
public bool Equals(Class_reglement x, Class_reglement y)
{
return x.Numf == y.Numf;
}
마지막으로, ToList
호출은 불필요하고 시간이 많이 소요입니다 : AddRange
어떤 받아 IEnumerable
A가 너무 변환 List
필요하지 않습니다. AsEnumerable
되어 도 에 결과 처리하기 때문에 여기에 중복 AddRange
어쨌든이 원인이됩니다.
1 실제로하는 일을 모르고 코드를 작성하는 것을 화물 컬트 프로그래밍 이라고 합니다 . 놀랍도록 널리 퍼진 관행입니다. 근본적으로 작동하지 않습니다.
답변
이 코드를 시도하십시오.
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();
답변
구현 GetHashCode
및 NULL
유효성 검사를 통해 코드 만 작성하십시오 .
public class Class_reglementComparer : IEqualityComparer<Class_reglement>
{
public bool Equals(Class_reglement x, Class_reglement y)
{
if (x is null || y is null))
return false;
return x.Numf == y.Numf;
}
public int GetHashCode(Class_reglement product)
{
//Check whether the object is null
if (product is 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;
}
}
예 : Numf에 의해 구별되는 Class_reglement 목록
List<Class_reglement> items = items.Distinct(new Class_reglementComparer());
답변
비교 클래스 (또는 더 구체적 AsEnumerable
으로 작동하기 위해 사용해야 하는 호출)를 포함한다는 것은 정렬 논리가 데이터베이스 서버 기반에서 데이터베이스 클라이언트 (응용 프로그램)에 있다는 것을 의미합니다. 즉, 클라이언트는 이제 더 많은 수의 레코드를 검색 한 다음 처리해야하므로 적절한 인덱스를 사용할 수있는 데이터베이스에서 조회를 수행하는 것보다 항상 효율성이 떨어집니다.
대신 요구 사항을 충족하는 where 절을 개발해야합니다 . 자세한 내용 은 LINQ to Entities Except 절과 함께 IEqualityComparer 사용 을 참조하세요.
답변
권투없이 일반적인 솔루션을 원하는 경우 :
public class KeyBasedEqualityComparer<T, TKey> : IEqualityComparer<T>
{
private readonly Func<T, TKey> _keyGetter;
public KeyBasedEqualityComparer(Func<T, TKey> keyGetter)
{
_keyGetter = keyGetter;
}
public bool Equals(T x, T y)
{
return EqualityComparer<TKey>.Default.Equals(_keyGetter(x), _keyGetter(y));
}
public int GetHashCode(T obj)
{
TKey key = _keyGetter(obj);
return key == null ? 0 : key.GetHashCode();
}
}
public static class KeyBasedEqualityComparer<T>
{
public static KeyBasedEqualityComparer<T, TKey> Create<TKey>(Func<T, TKey> keyGetter)
{
return new KeyBasedEqualityComparer<T, TKey>(keyGetter);
}
}
용법:
KeyBasedEqualityComparer<Class_reglement>.Create(x => x.Numf)
답변
IEquatable<T>
최신 프레임 워크를 사용하면이 작업을 훨씬 쉽게 수행 할 수 있습니다.
멋진 간단한 bool Equals(T other)
함수를 얻을 수 있으며 캐스팅하거나 별도의 클래스를 만드는 데 방해가 되지 않습니다.
public class Person : IEquatable<Person>
{
public Person(string name, string hometown)
{
this.Name = name;
this.Hometown = hometown;
}
public string Name { get; set; }
public string Hometown { get; set; }
// can't get much simpler than this!
public bool Equals(Person other)
{
return this.Name == other.Name && this.Hometown == other.Hometown;
}
public override int GetHashCode()
{
return Name.GetHashCode(); // see other links for hashcode guidance
}
}
GetHashCode
이것을 사전에서 사용 하는 경우 또는 Distinct
.
추신. 사용자 지정 Equals 메서드가 데이터베이스 측에서 직접 엔터티 프레임 워크와 작동하지 않는다고 생각합니다 (AsEnumerable을 수행하기 때문에 이것을 알고 있다고 생각합니다). 이것은 일반적인 경우에 대해 간단한 Equals를 수행하는 훨씬 간단한 방법입니다.
일이 작동하지 않는 것 같으면 (예 : ToDictionary를 수행 할 때 중복 키 오류) Equals 안에 중단 점을 넣어 그것이 적중되고 있는지 확인하고 GetHashCode
(override 키워드로) 정의 했는지 확인하십시오 .