我一直在尝试为不同的IEnumerable<T>
对象添加新的扩展方法。用于学习和应用目的。
背后的逻辑应该做这样的事情:(这有效)
// sis is a DbContext by the way
List<MyObj> objs = sis.MyObjs.ToList();
// objs contains duplicate entities
List<MyObj> _objs = new List<MyObj>();
foreach(MyObj e in MyObjs)
{
if (_ems.Contains(e) == false) _ems.Add(e);
}
foreach(MyObj e in _ems)
{
Console.WriteLine(e.ID); // Distinction happens
}
我已经写了一个新的扩展方法,就像上面的行一样。
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> en)
{
foreach(T f in en)
{
if (en.Contains(f) == false) yield return f;
}
}
但它没有用。奇怪的是,我也试过这些(单独)
objs.Distinct(); // default Distinct() method in Linq
objs.GroupBy(t => t.ID).Select(t => t.FirstOrDefault());
但他们也无法区分对象。唯一有效的,我在上面写的第一个逻辑。
那么,怎么可能写一个新的扩展来做与第一个逻辑相同的事情呢?
答案 0 :(得分:3)
这完全取决于T
实施Equals
和GetHashCode
的方式。如果实现是从object
继承的默认值,那么这将是引用相等。
除非T
具有string
之类的不变性,否则所有实例都会有所不同,它们会有不同的引用。
您可以为Distinct
方法添加重载,以接受IEqualityComparer<T>
实现来覆盖T
的行为。
Additionaly ,您当前的实现更多是存在剥离器,请参阅下面的建议替代方案。
public static IEnumerable<T> Distinct<T>(
this IEnumerable<T> source,
IEqualityComparer<T> comparer = null)
{
if (comparer == null)
{
comparer = EqualityComparer<T>.Default;
}
var seen = new HashSet<T>(comparer);
foreach (var t in source)
{
if (seen.Contains(t))
{
continue;
}
yield return t;
seen.Add(t);
}
}
答案 1 :(得分:0)
使用List和Dictionaries时,请记住在您要使用的T实体中重写Equals和GetHashCode。
在上面的示例中,您要比较引用(地址)而不是这些地址的预期值。