IEnumerable <t> </t>的新的不同扩展方法

时间:2014-03-20 11:09:08

标签: c# linq lambda extension-methods

我一直在尝试为不同的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());

但他们也无法区分对象。唯一有效的,我在上面写的第一个逻辑。

那么,怎么可能写一个新的扩展来做与第一个逻辑相同的事情呢?

2 个答案:

答案 0 :(得分:3)

这完全取决于T实施EqualsGetHashCode的方式。如果实现是从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。

在上面的示例中,您要比较引用(地址)而不是这些地址的预期值。