C# 无法通过GroupBy和ToDictionary转换LINQ结果返回Dictionary报错
问题原因
编译错误的核心原因有两个:
- 你分组时用的
new { Lat = g.Latitude, Lon = g.Longitude }是编译器自动生成的匿名类型,这类类型没有可供开发者在方法签名中显式书写的类型名,ReSharper自动提取方法时无法补全Dictionary的第一个泛型参数,才会生成Dictionary<, List<GpsPing>>这种非法的泛型声明,直接触发语法错误。 - 你原代码中
x.Select(g => g)返回的是IEnumerable<GpsPing>,和方法签名里声明的List<GpsPing>类型不匹配,就算键类型正确这里也会报类型转换错误。
修复方案
根据你的项目C#版本选择对应方案即可:
- 方案1(推荐,可维护性最高):定义强类型键替代匿名类型
首先定义专门的坐标键类型,注意必须实现值相等逻辑,否则字典查找、分组匹配会出现异常:
然后修改方法签名和逻辑,匹配强类型:// C# 9.0及以上版本可以直接用record,自动生成值相等逻辑 public record GpsPointKey(decimal Latitude, decimal Longitude); // C# 9.0以下版本手动实现类的相等判断 public class GpsPointKey { public decimal Latitude { get; } public decimal Longitude { get; } public GpsPointKey(decimal lat, decimal lon) { Latitude = lat; Longitude = lon; } public override bool Equals(object obj) => obj is GpsPointKey key && Latitude == key.Latitude && Longitude == key.Longitude; public override int GetHashCode() => HashCode.Combine(Latitude, Longitude); }private static Dictionary<GpsPointKey, List<GpsPing>> GetGpsPingsDictionary(IEnumerable<GpsPing> tractorPings) { return tractorPings .GroupBy(g => new GpsPointKey(g.Latitude, g.Longitude)) .ToDictionary(g => g.Key, g => g.ToList()); } - 方案2(无需额外定义类型,C# 7.0及以上可用):用值元组作为键
值元组自带值相等语义,可以直接写在泛型签名中,不需要额外定义类型:private static Dictionary<(decimal Lat, decimal Lon), List<GpsPing>> GetGpsPingsDictionary(IEnumerable<GpsPing> tractorPings) { return tractorPings .GroupBy(g => (g.Latitude, g.Longitude)) .ToDictionary(g => g.Key, g => g.ToList()); }
注意:不要为了省事故意把返回值键类型写为
object,匿名类型的访问级别是internal,跨程序集调用时会抛出类型访问异常,同时会丢失编译时类型检查,存在长期隐患。
内容的提问来源于stack exchange,提问作者Rafael Bolaños
相关产品推荐
相关产品推荐

