求助:导出含嵌套结构体的RecordSample集合至CSV丢失属性
解决CsvHelper导出CSV时未包含object类型结构体属性的问题
问题原因
你遇到的核心问题是:CsvHelper序列化RecordSample类时,data属性的类型是object,它无法自动识别这个object实际对应的具体结构体(如EulerAnglesMessage或QuaternionMessage),因此只会导出record_time_ms、record_id这两个明确类型的属性,而忽略data内部的结构体属性。
解决方案
由于同个字典键下的data类型一致,我们可以通过反射或泛型的方式,手动展开data的属性并写入CSV。以下是两种可行的实现方式:
方式一:反射动态处理任意结构体类型
这种方式无需提前枚举所有可能的结构体类型,通用性更强:
private static void ExportRecordedData() { foreach (var kvp in _recordedData) { string key = kvp.Key; var samples = kvp.Value; if (samples.Count == 0) continue; string path = $"{export_path}\\{key}.csv"; using (var writer = new StreamWriter(path)) using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) { // 获取当前键下data的实际类型 Type dataType = samples[0].data.GetType(); // 写入表头:先写RecordSample的属性,再写data结构体的属性 csv.WriteField("record_time_ms"); csv.WriteField("record_id"); foreach (var prop in dataType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { csv.WriteField(prop.Name); } csv.NextRecord(); // 遍历每个样本,写入完整数据 foreach (var sample in samples) { csv.WriteField(sample.record_time_ms); csv.WriteField(sample.record_id); foreach (var prop in dataType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { csv.WriteField(prop.GetValue(sample.data)); } csv.NextRecord(); } } } }
方式二:泛型方法实现类型安全导出
如果已知所有可能的结构体类型,这种方式更具类型安全性:
// 泛型导出方法,处理特定类型的data private static void ExportSamples<T>(List<RecordSample> samples, string path) { using (var writer = new StreamWriter(path)) using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) { // 写入表头 csv.WriteField("record_time_ms"); csv.WriteField("record_id"); foreach (var prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)) { csv.WriteField(prop.Name); } csv.NextRecord(); // 写入每条数据 foreach (var sample in samples) { var typedData = (T)sample.data; csv.WriteField(sample.record_time_ms); csv.WriteField(sample.record_id); foreach (var prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)) { csv.WriteField(prop.GetValue(typedData)); } csv.NextRecord(); } } } // 主导出方法 private static void ExportRecordedData() { foreach (var kvp in _recordedData) { string key = kvp.Key; var samples = kvp.Value; if (samples.Count == 0) continue; string path = $"{export_path}\\{key}.csv"; Type dataType = samples[0].data.GetType(); // 根据实际类型调用对应泛型方法 if (dataType == typeof(EulerAnglesMessage)) { ExportSamples<EulerAnglesMessage>(samples, path); } else if (dataType == typeof(QuaternionMessage)) { ExportSamples<QuaternionMessage>(samples, path); } // 新增结构体类型时,在此添加分支即可 } }
内容的提问来源于stack exchange,提问作者Eledwin
相关产品推荐
相关产品推荐

