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();
The inclusion of your comparison class (or more specifically the AsEnumerable
call you needed to use to get it to work) meant that the sorting logic went from being based on the database server to being on the database client (your application). This meant that your client now needs to retrieve and then process a larger number of records, which will always be less efficient that performing the lookup on the database where the approprate indexes can be used.
You should try to develop a where clause that satisfies your requirements instead, see Using an IEqualityComparer with a LINQ to Entities Except clause for more details.
Just code, with implementation of GetHashCode
and NULL
validation:
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;
}
}
Example: list of Class_reglement distinct by Numf
List<Class_reglement> items = items.Distinct(new Class_reglementComparer());
If you want a generic solution without boxing:
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);
}
}
usage:
KeyBasedEqualityComparer<Class_reglement>.Create(x => x.Numf)
IEquatable<T>
can be a much easier way to do this with modern frameworks.
You get a nice simple bool Equals(T other)
function and there's no messing around with casting or creating a separate class.
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
}
}
Note you DO have to implement GetHashCode
if using this in a dictionary or with something like Distinct
.
PS. I don't think any custom Equals methods work with entity framework directly on the database side (I think you know this because you do AsEnumerable) but this is a much simpler method to do a simple Equals for the general case.
If things don't seem to be working (such as duplicate key errors when doing ToDictionary) put a breakpoint inside Equals to make sure it's being hit and make sure you have GetHashCode
defined (with override keyword).
참고URL : https://stackoverflow.com/questions/6694508/how-to-use-the-iequalitycomparer
'programing tip' 카테고리의 다른 글
C #에서 XmlReader로 Xml 읽기 (0) | 2020.09.05 |
---|---|
OrderBy 파이프 문제 (0) | 2020.09.05 |
Notepad ++에서 플러그인 관리자를 보는 방법 (0) | 2020.09.05 |
쉘 파이프에서 오류 코드 포착 (0) | 2020.09.05 |
서블릿 기반 웹 애플리케이션에서 백그라운드 작업을 실행하는 방법은 무엇입니까? (0) | 2020.09.05 |