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

8

我不知道 LinqQuery.ToList().Distinct()LinqQuery.Distinct().ToList(); 之间的区别,对于我来说两者看起来都一样。

考虑下面的示例代码:

List<string> stringList = new List<string>();

List<string> str1  = (from item in stringList
                                select item).ToList().Distinct();

List<string> str2 = (from item in stringList
                                 select item).Distinct().ToList();

str1显示错误为:“无法隐式将类型'System.Collections.Generic.IEnumerable'转换为类型'System.Collections.Generic.List'。存在显式转换(是否缺少强制转换?)”

但是,str2没有错误。

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


2
“throws” 常用于描述在运行时发生的错误(通常是异常)。而这是一个编译时错误。 - Damien_The_Unbeliever
1个回答

19

.Distinct() 是一个作用于 IEnumerable<T> 的方法,返回一个 IEnumerable<T>(惰性求值)。IEnumerable<T> 是一个序列:它不是一个 List<T>。因此,如果您想要得到一个列表,请在末尾加上 .ToList()

// note: this first example does not compile
List<string> str1  = (from item in stringList
                            select item) // result: IEnumerable<string>
                         .ToList() // result: List<string>
                         .Distinct(); // result: IEnumerable<string>

List<string> str2 = (from item in stringList
                             select item) // result: IEnumerable<string>
                         .Distinct() // result: IEnumerable<string>
                         .ToList(); // result: List<string>

为了说明这一点,考虑以下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 == new value we haven't seen before
            yield return value;
        }
    }
}

为了让 str1 正常工作,请在末尾添加 "ToList()"。这样它看起来就像这样:xxx.ToList().Distinct().ToList()。 - Marty
2
@Marty 这将是不可取的;它会在中间创建一个不必要的列表;现有的 str2 代码更可取。 - Marc Gravell
是的,我明白。只需将此放入其中,以更好地理解如何使其工作 :) - Marty
请注意 - 如果您处理的是对象而不是字符串,则Marc的str2与Marty的ToList().Distinct().ToList()注释不等同。这取决于项目对象的类型。我有一个场景,其中Distinct()项与Distinct()选择不是同一件事。 - Paul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接