为什么 .ToList().Distinct() 抛出错误,而 .Distinct().ToList() 不会在使用linq查询时抛出错误。

16 浏览
0 Comments

为什么 .ToList().Distinct() 抛出错误,而 .Distinct().ToList() 不会在使用linq查询时抛出错误。

我无法区分 LinqQuery.ToList().Distinct()LinqQuery.Distinct().ToList();之间的区别,对我来说两者看起来相同。

考虑下面的示例代码:

List stringList = new List();
List str1  = (from item in stringList
                                select item).ToList().Distinct();
List str2 = (from item in stringList
                                 select item).Distinct().ToList();

str1显示错误信息:"无法将类型'System.Collections.Generic.IEnumerable'隐式转换为'System.Collections.Generic.List'。存在一个显式转换(是否遗漏了一个转换?)"

但是str2没有错误。

请帮助我理解这两者之间的区别。

谢谢

0
0 Comments

为什么使用LINQ查询时,.ToList().Distinct()会报错,而.Distinct().ToList()不会报错?

问题出现的原因是,.Distinct()是一个在IEnumerable<T>上操作的方法,并且返回一个IEnumerable<T>(延迟评估)。IEnumerable<T>是一个序列,它不是List<T>。因此,如果你想要得到一个列表,把.ToList()放在最后。

为了说明这个问题,我们来看一个简单的Distinct()的实现:

public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source) {
    var seen = new HashSet<T>();
    foreach(var value in source) {
        if(seen.Add(value)) { // true表示新值
            yield return value;
        }
    }
}

为了让str1能够正常工作,需要在最后添加.ToList()。所以它应该是这样的:xxx.ToList().Distinct().ToList()。但这样做是不可取的,因为它创建了一个不必要的列表;现有的str2的代码是更好的选择。

值得注意的是,如果处理的是对象而不是字符串,Marc的str2和Marty的ToList().Distinct().ToList()是不等价的。这取决于item的对象类型。在某些情况下,Distinct()的项与Distinct()的选择不是相同的对象。

解决方法就是将.ToList()放在.Distinct()之后,这样可以确保最终得到的是一个列表。

0