如何提取CSV每行有数据的列头?解决ExpandoObject索引报错
问题与解决方案
问题描述
需要提取CSV文件中每行存在数据的列头(示例:第一行Column B、Column D无数据,输出Column A、Column C;第二行Column C无数据,输出Column A、Column B、Column D)。使用CsvReader读取CSV到dynamic列表时触发错误:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'Cannot apply indexing with [] to an expression of type 'System.Dynamic.ExpandoObject''
原代码如下:
string csvFilePath = "your_csv_file.csv"; using (var reader = new StreamReader(csvFilePath)) using (var csv = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture))) { // Read the CSV records into a dynamic list var records = csv.GetRecords<dynamic>().ToList(); // Get the headers from the first record var headers = ((IDictionary<string, object>)records[0]).Keys.ToList(); // Create a list to store headers with data var headersWithData = new List<string>(); // Iterate through headers and check if any row in the column has data foreach (var header in headers) { if (records.Skip(1).Any(record => !string.IsNullOrWhiteSpace(record[header]?.ToString()))) { headersWithData.Add(header); } } // Print the filtered column headers with data Console.WriteLine("Column Headers with Data:"); foreach (var header in headersWithData) { Console.WriteLine(header); } }
解决方案
错误根源是dynamic类型的ExpandoObject不支持直接用[]索引访问,需将其强制转换为IDictionary<string, object>接口后再操作。修改后的代码如下:
string csvFilePath = "your_csv_file.csv"; using (var reader = new StreamReader(csvFilePath)) using (var csv = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture))) { var records = csv.GetRecords<dynamic>().ToList(); var headers = ((IDictionary<string, object>)records[0]).Keys.ToList(); var headersWithData = new List<string>(); foreach (var header in headers) { // 将record强制转换为IDictionary<string, object>后再访问键值 if (records.Skip(1).Any(record => !string.IsNullOrWhiteSpace(((IDictionary<string, object>)record)[header]?.ToString()))) { headersWithData.Add(header); } } Console.WriteLine("Column Headers with Data:"); foreach (var header in headersWithData) { Console.WriteLine(header); } }
关键修改点
在判断每行对应列是否有数据时,将record[header]替换为((IDictionary<string, object>)record)[header]——因为ExpandoObject本身实现了IDictionary<string, object>接口,强制转换后即可通过键名(列头)访问对应的值。
内容的提问来源于stack exchange,提问作者Brown
相关产品推荐
相关产品推荐

