C# DistinctBy与Distinct的区别
你想了解在C[#中对反序列化得到的](javascript:😉Vehicle列表使用DistinctBy和Distinct方法的核心区别,尤其是在按字段去重场景下两者的行为差异。
一、核心区别详解
首先需要明确:这两个方法都是LINQ中用于去重的方法,但去重的判断逻辑和使用方式完全不同,结合你的代码场景逐一说明:
1. 先补全必要的Vehicle类定义
你的代码中用到了Vehicle类,但未展示定义,先补充完整(保证代码可运行):
using DistinctDemo;using Newtonsoft.Json;using System.Collections.Generic;using System.Linq;// 补全Vehicle类定义namespaceDistinctDemo{public class Vehicle { [JsonProperty("number")]public string Number { get; set; } [JsonProperty("vehicleNo")]public string VehicleNo { get; set; } [JsonProperty("statusEnum")]public int StatusEnum { get; set; } [JsonProperty("status")]public string Status { get; set; } [JsonProperty("createdDateTime")]public DateTime CreatedDateTime { get; set; } }}Console.WriteLine("Hello, World!");var json = $"
[
{
"number": "202601210010",
"vehicleNo": "鲁H232H0",
"statusEnum": 1,
"status": "厂外",
"createdDateTime": "2026-01-21T11:42:56.060242"
},
{
"number": "202601210010",
"vehicleNo": "鲁H232H0",
"statusEnum": 1,
"status": "厂外",
"createdDateTime": "2026-01-21T11:42:56.060242"
},
{
"number": "202601210010",
"vehicleNo": "鲁H232H0",
"statusEnum": 1,
"status": "厂外",
"createdDateTime": "2026-01-21T11:42:56.060242"
},
{
"number": "202601210010",
"vehicleNo": "鲁H232H0",
"statusEnum": 1,
"status": "厂外",
"createdDateTime": "2026-01-21T11:42:56.060242"
},
{
"number": "202601210010",
"vehicleNo": "鲁H232H0",
"statusEnum": 1,
"status": "厂外",
"createdDateTime": "2026-01-21T11:42:56.060242"
},
{
"number": "202601210011",
"vehicleNo": "鄂B5B818",
"statusEnum": 1,
"status": "厂外",
"createdDateTime": "2026-01-21T12:48:24.246919"
}
]
";var vehicles = JsonConvert.DeserializeObject<List<Vehicle>>(json);// 按Number字段去重var v2 = vehicles.DistinctBy(r => r.Number).ToList();// 默认按对象实例去重(无效果)var v3 = vehicles.Distinct().ToList();Console.WriteLine($"原列表数量:{vehicles.Count}"); // 输出 6Console.WriteLine($"DistinctBy去重后数量:{v2.Count}"); // 输出 2(202601210010 和 202601210011)Console.WriteLine($"Distinct去重后数量:{v3.Count}"); // 输出 6(无去重效果)
2. Distinct() 方法
-
核心逻辑
:判断整个对象是否完全相等,默认规则:
-
对于值类型(如int、string):按“值”相等判断;
-
对于自定义引用类型(如
Vehicle):按“引用地址”相等判断(即只有同一个对象实例才会被判定为重复)。 -
你的场景表现
:你反序列化得到的6个
Vehicle对象都是独立的实例(即使字段值完全相同),所以Distinct()会认为所有对象都不重复,最终返回6个对象,无去重效果。 -
要让Distinct按字段去重
:必须自定义相等逻辑(重写
Equals和GetHashCode,或传入IEqualityComparer<Vehicle>),示例:```
// 自定义比较器:按Number字段判断相等
public class VehicleNumberComparer : IEqualityComparer
{
public bool Equals(Vehicle x, Vehicle y)
{
if (x == null || y == null) returnfalse;
return x.Number == y.Number;
}public int GetHashCode(Vehicle obj)
{
return obj.Number.GetHashCode();
}
}// 使用自定义比较器的Distinct
var v4 = vehicles.Distinct(new VehicleNumberComparer()).ToList();
Console.WriteLine($"自定义Distinct去重后数量:{v4.Count}"); // 输出 2
3. DistinctBy<TKey>() 方法
-
核心逻辑
:.NET 6+ 新增方法,允许指定一个键选择器(Key Selector),按“指定字段/属性的值”去重,无需修改
Vehicle类或自定义比较器。 -
你的场景表现
:
DistinctBy(r => r.Number)会提取每个Vehicle的Number字段,只要Number值相同就判定为重复,最终只保留每个Number的第一个对象,所以返回2个对象(202601210010 和 202601210011)。 -
灵活性
:可按任意字段/组合字段去重,比如按
Number + VehicleNo组合去重:```
var v5 = vehicles.DistinctBy(r => $"{r.Number}_{r.VehicleNo}").ToList();
二、关键差异对比表
|
特性
|
Distinct()
|
DistinctBy()
|
| --- | --- | --- |
|
去重依据
|
整个对象的相等性(默认按引用)
|
指定字段/属性的键值
|
|
.NET 版本要求
|
所有版本
|
.NET 6+
|
|
使用复杂度
|
需自定义比较器(按字段去重时)
|
直接指定键选择器,简洁易用
|
|
你的代码执行结果
|
返回6个对象(无去重)
|
返回2个对象(按Number去重)
|
总结
-
Distinct()
是“对象级去重”,默认比较引用,按字段去重需自定义相等逻辑,适配所有.NET版本;
-
DistinctBy()
是“字段级去重”,.NET 6+ 新增,通过键选择器直接指定去重字段,无需修改实体类,使用更简洁;
-
在你的场景中,要按
Number去重,DistinctBy(r => r.Number)是最优选择(无需额外代码),而Distinct()默认无效果,需自定义比较器才能实现相同效果。

浙公网安备 33010602011771号