C# foreach遍历KeyValuePair时如何读取struct内容写入txt文件
问题根因
直接将结构体对象传入WriteLine格式化参数时,默认调用object.ToString()方法,未重写ToString()的值类型会直接返回类型全名称,也就是你看到的结构体名称,无法输出实际字段/属性值。
另外你现有代码存在逻辑错误:在内层循环第一次执行时就调用了tw2.Close(),后续循环写入时会触发流已释放的异常。
基础写入功能修复
通过递归解析方法处理任意类型的输入值,对结构体/自定义类型通过反射读取公开实例的属性和字段内容,同时修正流释放的逻辑,代码如下:
private void show2(Dictionary<string, object> state) { // using语句会在执行完毕后自动释放流资源,无需手动调用Close using TextWriter tw2 = new StreamWriter(savepath2); foreach (KeyValuePair<string, object> group1 in state) { // 增加类型判断,避免值不符合预期时强转报错 if (group1.Value is not Dictionary<string, object> group2) { tw2.WriteLine($"Id: {group1.Key} -- 非字典类型值: {ParseObjectValue(group1.Value)}"); continue; } foreach (KeyValuePair<string, object> innerKey in group2) { tw2.WriteLine("Id: {0} -- Type: {1} -- Value: {2}", group1.Key, innerKey.Key, ParseObjectValue(innerKey.Value)); } } } /// <summary> /// 递归解析任意对象为可读字符串 /// </summary> private string ParseObjectValue(object obj) { if (obj == null) return "null"; Type objType = obj.GetType(); // 基础值类型、字符串直接返回ToString结果 if (obj is string || objType.IsPrimitive || obj is decimal || obj is DateTime) { return obj.ToString(); } // 嵌套字典递归解析 if (obj is Dictionary<string, object> dict) { var dictContent = dict.Select(kv => $"{kv.Key}:{ParseObjectValue(kv.Value)}"); return $"{{{string.Join(", ", dictContent)}}}"; } // 结构体、自定义类通过反射读取所有公开实例属性、字段 if (objType.IsValueType || objType.IsClass) { List<string> memberValues = new List<string>(); // 读取公开属性,跳过索引器 foreach (var prop in objType.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)) { if (prop.GetIndexParameters().Length > 0) continue; object val = prop.GetValue(obj); memberValues.Add($"{prop.Name}={ParseObjectValue(val)}"); } // 读取公开字段 foreach (var field in objType.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)) { object val = field.GetValue(obj); memberValues.Add($"{field.Name}={ParseObjectValue(val)}"); } return $"{objType.Name}:{{{string.Join(", ", memberValues)}}}"; } return obj.ToString(); }
纯文本可读序列化方案
BinaryFormatter已经被官方标记为不安全类型,不推荐继续使用。如果需要直接生成可直接打开查看的文本格式存储嵌套结构,优先使用JSON序列化,输出为带缩进的格式化纯文本,天然支持嵌套字典、结构体等所有常规类型,流写入实现简单:
// .NET Core 3.0+/.NET 5+ 自带System.Text.Json,.NET Framework可通过NuGet安装对应包 private void SaveFile(object state) { using var stream = File.Open(savepath, FileMode.Create); using var writer = new StreamWriter(stream); string jsonContent = System.Text.Json.JsonSerializer.Serialize(state, new JsonSerializerOptions() { WriteIndented = true, // 开启缩进排版,生成的文件结构清晰可读 Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping // 避免中文等非ASCII字符被转义 }); writer.Write(jsonContent); }
- 如果需要输出结构体的非公开成员,修改反射逻辑的
BindingFlags参数,加上NonPublic枚举即可 - JSON序列化方案兼容性更强,可通过配置
MaxDepth参数限制递归深度,避免循环引用导致的栈溢出 - 禁止在循环内释放写入流,否则会导致后续写入操作失败
内容的提问来源于stack exchange,提问作者hesam gol
相关产品推荐
相关产品推荐

