如何修复含Distinct()的LINQ表达式编译错误?
我正在开发一个C#控制台应用程序,将.CSV文件的数据读取到自定义对象列表中,并用LINQ进行处理。程序大部分编译正常,但在两处提取唯一值并写入文本文件的代码行出现编译错误。
具体来说,IDE在我尝试使用.Distinct()和.ForEach()的LINQ链末尾抛出编译错误。有趣的是,代码中之前使用számlák.Select(x => x.PályázatKód).Distinct().Count()的类似查询完全正常,但当我尝试用StreamWriter遍历去重值写入文件时,编译器拒绝执行。错误似乎出现在Distinct().ForEach(...)的转换环节,但我无法确定具体的类型不匹配或缺失引用问题。
背景信息:我的Szamla类已正确定义,包含标准自动实现属性和可用构造函数。数据已从szamlak.csv文件正确读取,Count()和Sum()等操作执行正常,且文件顶部已引入System.Linq命名空间。
我对Distinct()向下传递数据的机制有什么误解?如何正确遍历过滤后的结果写入输出文件?
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace VizsgaKonzol { internal class Szamla { private string pályázatKód; private string számlaszám; private string dátum; private int érték; private string költségTípus; public string PályázatKód { get => pályázatKód; set => pályázatKód = value; } public string Számlaszám { get => számlaszám; set => számlaszám = value; } public string Dátum { get => dátum; set => dátum = value; } public int Érték { get => érték; set => érték = value; } public string KöltségTípus { get => költségTípus; set => költségTípus = value; } public Szamla(string pályázatKód, string számlaszám, string dátum, int érték, string költségTípus) { this.pályázatKód = pályázatKód; this.számlaszám = számlaszám; this.dátum = dátum; this.érték = érték; this.költségTípus = költségTípus; } public override string ToString() { return $"{pályázatKód}: {dátum} - {érték} Ft - {számlaszám} - {költségTípus}"; } } }
using System.IO; using VizsgaKonzol; List<Szamla> számlák = new List<Szamla>(); using (StreamReader reader = new StreamReader("szamlak.csv")) { reader.ReadLine(); while (!reader.EndOfStream) { string[] line = reader.ReadLine().Split(';'); számlák.Add(new Szamla(line[0], line[1], line[2], int.Parse(line[3]), line[4])); } } var a = számlák.OrderBy(x => x.PályázatKód); Console.WriteLine("3. feladat:\n\tA fájl beolvasása és eltárolása kész."); Console.WriteLine($"4. feladat:\n\tA fájlban lévő számlák darabszáma: {számlák.Count}."); Console.WriteLine($"5. feladat:\n\tA számlák összértéke: {számlák.Sum(x => x.Érték).ToString("##,#")} Ft."); Console.WriteLine($"6. feladat:\n\t{számlák.Select(x => x.PályázatKód).Distinct().Count()} db különböző pályázat készült."); using (StreamWriter sw = new StreamWriter("kodok.txt")) { // 原错误代码:számlák.OrderBy(x => x.PályázatKód).Select(x => x.PályázatKód).Distinct().ForEach(x => sw.Write($"{x}\n")); // 修正方式1:转为List后调用ForEach számlák.OrderBy(x => x.PályázatKód).Select(x => x.PályázatKód).Distinct().ToList().ForEach(x => sw.WriteLine(x)); } Console.WriteLine("3. feladat:\n\tA kodok.txt fájl kész."); using (StreamWriter sw = new StreamWriter("koltseg_tipusok.txt")) { // 同样修正 számlák.OrderBy(x => x.KöltségTípus).Select(x => x.KöltségTípus).Distinct().ToList().ForEach(x => sw.WriteLine(x)); } Console.WriteLine("3. feladat:\n\tA koltseg_tipusok.txt fájl kész."); Console.Write("9. feladat:\n\tAdja meg a keresett pályázat sorszámát: "); string beker = Console.ReadLine(); if (beker.Length > 3) { Console.WriteLine("nem megfelelő számformátum, max 3 jegyű lehet!"); } else { string nulla = ""; for (int i = 0; i < 3 - beker.Length; i++) { nulla += "0"; } nulla += beker; beker = nulla; } List<Szamla> szűrt = számlák.Where(x => x.PályázatKód == $"P-{beker}").OrderBy(x => x.Dátum).ToList(); if (szűrt.Count > 0) { szűrt.ForEach(x => Console.WriteLine($"\t{x.ToString()}")); Console.WriteLine($"\tÖsszesen {szűrt.Count} db számla tartozik hozzá."); } else { Console.WriteLine($"\tNincs ilyen pályázat: P-{beker}!"); }
核心原因
Distinct()方法返回的是IEnumerable<T>类型,而**IEnumerable<T>并没有内置的ForEach()方法**——你之前能用ForEach()是因为调用的是List<T>的实例方法,而LINQ链式调用到Distinct()之后已经不再是List<T>类型了。
之前的Count()能正常工作,是因为Count()是LINQ为IEnumerable<T>提供的扩展方法,和List<T>的Count属性/方法是两回事。
两种修正方式
- 转换为List
后调用ForEach
在Distinct()之后追加.ToList(),将IEnumerable<T>转换为List<T>,这样就能调用List<T>的ForEach()实例方法:számlák.OrderBy(x => x.PályázatKód).Select(x => x.PályázatKód).Distinct().ToList().ForEach(x => sw.WriteLine(x)); - 使用标准foreach循环
直接遍历IEnumerable<T>结果,这也是更符合C#常规写法的方式:foreach (var kod in számlák.OrderBy(x => x.PályázatKód).Select(x => x.PályázatKód).Distinct()) { sw.WriteLine(kod); }
额外注意点
原Program.cs代码中缺少System.IO命名空间的引用,StreamReader和StreamWriter需要这个命名空间才能正常编译,记得添加:
using System.IO;
内容的提问来源于stack exchange,提问作者user32743109

