Distinct()对值类型和重写Equals/GetHashCode的类型直接有效,但List等引用类型需实现IEqualityComparer或用.NET6+的DistinctBy()按属性去重,避免性能陷阱和null/大小写问题。
用 Distinct() 去重最直接,但要注意引用类型默认不生效
对 list<int></int> 或 list<string></string> 这类值类型或重写了 equals/gethashcode 的类型,distinct() 能直接去重。但如果你的 list<person></person> 里有多个属性相同的对象,默认调用的是引用比较——结果一个都去不掉。
- 值类型(如
int、DateTime)和字符串可直接用:list.Distinct().ToList() - 自定义类必须实现
IEqualityComparer<t></t>,或用DistinctBy()(.NET 6+) - 别在循环里反复调用
Distinct(),它每次都会遍历整个集合,O(n) 时间复杂度
DistinctBy() 是 .NET 6+ 最省事的字段级去重方案
想按某个属性(比如 Id 或 Email)去重?DistinctBy(x => x.Id) 比手写 IEqualityComparer 清晰得多,也比先 GroupBy 再取 First() 更高效。
- 仅适用于 .NET 6 及以上;低版本只能用
GroupBy(x => x.Id).Select(g => g.First()) - 注意:
DistinctBy返回第一个匹配项,顺序依赖原始List的排列 - 不能链式多次
DistinctBy,它只支持单个 key selector,多字段要用匿名类型:DistinctBy(x => new { x.Id, x.Name })
用 GroupBy + First() 兼容老版本,但性能稍差
在 .NET 5 或更早环境里,GroupBy 是最稳妥的选择。但它会把所有元素分组再取首项,内存占用和执行时间都高于 DistinctBy,尤其数据量大时明显。
- 写法示例:
list.GroupBy(x => x.Id).Select(g => g.First()).ToList() - 如果原始列表已排序且只需保留首次出现项,
GroupBy是安全的;否则结果顺序可能不符合直觉 - 避免写成
GroupBy(...).OrderBy(...).First()—— 这样会触发两次遍历,且OrderBy完全没必要
别忽略 null 值和大小写敏感问题
字符串去重时,"abc" 和 "ABC" 默认算两个不同元素;如果 list 里混着 null,Distinct() 会抛 NullReferenceException(除非你用了自定义比较器处理 null)。
- 忽略大小写:用
Distinct(StringComparer.OrdinalIgnoreCase) - 安全处理 null:在
IEqualityComparer<string></string>实现里显式判断a == null && b == null - 用
DistinctBy时,key selector 表达式本身若可能为 null(如x.Name),要提前做空检查或用 null 合并操作符:x.Name ?? string.Empty
Distinct() 对任意对象都“自动按内容去重”,结果调试半天发现对象没重写比较逻辑,或者忘了 .NET 版本限制。


















