编辑
2025-09-17
C#
00

目录

使用反射(Reflection)
特点
应用场景
代码示例
高级应用:属性过滤
使用Newtonsoft.Json
特点
应用场景
代码示例
高级应用:自定义序列化
特点
应用场景
代码示例
高级应用:自定义JsonSerializerOptions
使用LINQ和自定义逻辑
特点
应用场景
代码示例
高级应用:自定义键值转换
使用ExpandoObject
特点
应用场景
代码示例
高级应用:结合LINQ和ExpandoObject
性能比较
总结

在C#开发中,我们经常需要将Plain Old CLR Object (POCO)转换为Dictionary<string, object>。这种需求在与第三方API交互、序列化数据、动态数据处理等场景中尤为常见。本文将深入探讨五种不同的转换方法,分析它们的特点、适用场景,并提供详细的代码示例和性能比较。

使用反射(Reflection)

特点

  • 灵活性高,可以处理任何POCO对象
  • 不需要额外的依赖库
  • 性能较好,适合频繁使用的场景

应用场景

  • 动态处理未知类型的对象
  • 需要自定义属性过滤或转换逻辑
  • 框架开发,需要通用的对象处理机制

代码示例

C#
using System; using System.Reflection; namespace AppPOCO { public class Person { public string Name { get; set; } public int Age { get; set; } } internal class Program { static void Main(string[] args) { // 使用示例 var person = new Person { Name = "Alice", Age = 30 }; var dict = ConvertToDict(person); Console.WriteLine(dict["Name"]); Console.WriteLine(dict["Age"]); Console.ReadLine(); } public static Dictionary<string, object> ConvertToDict(object obj) { return obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public) .ToDictionary(prop => prop.Name, prop => prop.GetValue(obj)); } } }

image.png

高级应用:属性过滤

C#
using System; using System.Reflection; namespace AppPOCO { public class Person { public string Name { get; set; } public int Age { get; set; } } internal class Program { static void Main(string[] args) { // 使用示例 var person = new Person { Name = "Alice", Age = 30 }; var filteredDict = ConvertToDictFiltered(person, prop => prop.PropertyType == typeof(string)); Console.WriteLine(filteredDict["Name"]); Console.ReadLine(); } public static Dictionary<string, object> ConvertToDictFiltered(object obj, Func<PropertyInfo, bool> filter) { return obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public) .Where(filter) .ToDictionary(prop => prop.Name, prop => prop.GetValue(obj)); } } }

image.png

使用Newtonsoft.Json

特点

  • 利用成熟的JSON序列化库
  • 可以处理复杂的对象结构,包括嵌套对象和集合
  • 配置灵活,可以自定义序列化行为

应用场景

  • 处理包含复杂数据结构的对象
  • 需要在序列化和反序列化之间保持一致性
  • 已经在项目中使用Newtonsoft.Json库

代码示例

C#
using System; using System.Net; using System.Reflection; using Newtonsoft.Json; using static AppPOCO.Person; namespace AppPOCO { public class Person { public string Name { get; set; } public int Age { get; set; } public class Address { public string Street { get; set; } public string City { get; set; } } public Address address { get; set; } } internal class Program { static void Main(string[] args) { // 使用示例 var complexPerson = new Person { Name = "Bob", Age = 35, address = new Address { Street = "123 Main St", City = "Anytown" } }; var dict = ConvertToDictNewtonsoft(complexPerson); foreach (var item in dict) { Console.WriteLine($"{item.Key}: {item.Value}"); } Console.ReadLine(); } public static Dictionary<string, object> ConvertToDictNewtonsoft(object obj) { var json = JsonConvert.SerializeObject(obj); return JsonConvert.DeserializeObject<Dictionary<string, object>>(json); } } }

image.png

高级应用:自定义序列化

C#
using System; using System.Net; using System.Reflection; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using static AppPOCO.Person; namespace AppPOCO { public enum Gender { Male, Female } public class Person { public string Name { get; set; } public int Age { get; set; } public Gender Gender { get; set; } public class Address { public string Street { get; set; } public string City { get; set; } } public Address address { get; set; } } internal class Program { static void Main(string[] args) { // 使用示例 var person = new Person { Name = "Charlie", Gender = Gender.Male }; var dict = ConvertToDictNewtonsoftCustom(person); Console.WriteLine(JsonConvert.SerializeObject(dict)); Console.ReadLine(); } public static Dictionary<string, object> ConvertToDictNewtonsoftCustom(object obj) { var settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = new List<JsonConverter> { new StringEnumConverter() } }; var json = JsonConvert.SerializeObject(obj, settings); return JsonConvert.DeserializeObject<Dictionary<string, object>>(json, settings); } } }

image.png

使用System.Text.Json(C# 8.0+)

特点

  • .NET Core和.NET 5+的内置JSON库
  • 性能优于Newtonsoft.Json
  • 与.NET生态系统深度集成

应用场景

代码示例

C#
using System; using System.Net; using System.Reflection; using System.Text.Json; namespace AppPOCO { public enum Gender { Male, Female } public class Person { public string Name { get; set; } public int Age { get; set; } public Gender Gender { get; set; } public class Address { public string Street { get; set; } public string City { get; set; } } public Address address { get; set; } } internal class Program { static void Main(string[] args) { // 使用示例 var person = new Person { Name = "David", Age = 40 }; var dict = ConvertToDictSystemTextJson(person); Console.WriteLine(dict["Name"]); Console.WriteLine(dict["Age"]); Console.ReadLine(); } public static Dictionary<string, object> ConvertToDictSystemTextJson(object obj) { var json = JsonSerializer.Serialize(obj); return JsonSerializer.Deserialize<Dictionary<string, object>>(json); } } }

image.png

高级应用:自定义JsonSerializerOptions

C#
public static Dictionary<string, object> ConvertToDictSystemTextJsonCustom(object obj) { var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true }; var json = JsonSerializer.Serialize(obj, options); return JsonSerializer.Deserialize<Dictionary<string, object>>(json, options); }

使用LINQ和自定义逻辑

特点

  • 高度可定制
  • 不依赖外部库
  • 可以实现复杂的转换逻辑

应用场景

  • 需要对属性名或值进行特殊处理
  • 只需要转换特定的属性
  • 需要在转换过程中执行额外的逻辑

代码示例

C#
using System; using System.Net; using System.Reflection; using System.Text.Json; namespace AppPOCO { public enum Gender { Male, Female } public class Person { public string Name { get; set; } public int Age { get; set; } public Gender Gender { get; set; } public class Address { public string Street { get; set; } public string City { get; set; } } public Address address { get; set; } } internal class Program { static void Main(string[] args) { // 使用示例 var person = new Person { Name = "Frank", Age = 0 }; var dict = ConvertToDictLinq(person); Console.WriteLine(JsonSerializer.Serialize(dict)); Console.ReadLine(); } public static Dictionary<string, object> ConvertToDictLinq(object obj) { return obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public) .ToDictionary( prop => prop.Name, prop => prop.GetValue(obj) ?? "N/A" ); } } }

image.png

高级应用:自定义键值转换

C#
using System; using System.Net; using System.Reflection; using System.Text.Json; namespace AppPOCO { public enum Gender { Male, Female } public class Person { public string Name { get; set; } public int Age { get; set; } public Gender Gender { get; set; } public class Address { public string Street { get; set; } public string City { get; set; } } public Address address { get; set; } } internal class Program { static void Main(string[] args) { // 使用示例 var person = new Person { Name = "Grace", Age = 50 }; var dict = ConvertToDictLinqCustom(person); Console.WriteLine(JsonSerializer.Serialize(dict)); Console.ReadLine(); } public static Dictionary<string, object> ConvertToDictLinqCustom(object obj) { return obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public) .ToDictionary( prop => prop.Name.ToLower(), prop => prop.PropertyType == typeof(string) ? prop.GetValue(obj)?.ToString().ToUpper() : prop.GetValue(obj) ); } } }

image.png

使用ExpandoObject

特点

  • 支持动态添加和删除属性
  • 可以像使用动态对象一样使用字典
  • 适合需要频繁修改结构的场景

应用场景

  • 动态数据处理
  • 构建灵活的数据结构
  • 与动态语言交互

代码示例

C#
using System; using System.Dynamic; using System.Net; using System.Reflection; using System.Text.Json; namespace AppPOCO { public enum Gender { Male, Female } public class Person { public string Name { get; set; } public int Age { get; set; } public Gender Gender { get; set; } public class Address { public string Street { get; set; } public string City { get; set; } } public Address address { get; set; } } internal class Program { static void Main(string[] args) { // 使用示例 var person = new Person { Name = "Henry", Age = 45 }; dynamic expandoDict = ConvertToExpandoObject(person); Console.WriteLine(expandoDict.Name); // 输出: Henry expandoDict.Job = "Developer"; // 动态添加属性 Console.WriteLine(JsonSerializer.Serialize(expandoDict)); Console.ReadLine(); } public static dynamic ConvertToExpandoObject(object obj) { var expando = new ExpandoObject(); var expandoDic = (IDictionary<string, object>)expando; foreach (var prop in obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) { expandoDic.Add(prop.Name, prop.GetValue(obj)); } return expando; } } }

image.png

高级应用:结合LINQ和ExpandoObject

C#
using System; using System.Dynamic; using System.Net; using System.Reflection; using System.Text.Json; namespace AppPOCO { public enum Gender { Male, Female } public class Person { public string Email { get; set; } public string Name { get; set; } public int Age { get; set; } public Gender Gender { get; set; } public class Address { public string Street { get; set; } public string City { get; set; } } public Address address { get; set; } } internal class Program { static void Main(string[] args) { // 使用示例 var person = new Person { Name = "Ivy", Age = 0, Email = "ivy@example.com" }; dynamic filteredExpando = ConvertToExpandoObjectFiltered(person, prop => prop.GetValue(person) != null && !prop.GetValue(person).Equals(0)); Console.WriteLine(JsonSerializer.Serialize(filteredExpando)); Console.ReadLine(); } public static dynamic ConvertToExpandoObjectFiltered(object obj, Func<PropertyInfo, bool> filter) { var expando = new ExpandoObject(); var expandoDic = (IDictionary<string, object>)expando; obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public) .Where(filter) .ToList() .ForEach(prop => expandoDic.Add(prop.Name, prop.GetValue(obj))); return expando; } } }

image.png

性能比较

根据文章中提供的基准测试结果,我们可以得出以下结论:

  1. 反射方法和LINQ方法性能最佳,适合高频率调用的场景。
  2. ExpandoObject方法性能适中,在需要动态性的场景下是个不错的选择。
  3. JSON序列化方法(Newtonsoft.Json和System.Text.Json)性能较低,但在处理复杂对象时更为可靠。

总结

选择合适的POCO到Dictionary的转换方法取决于多个因素:

  • 性能需求
  • 对象复杂度
  • 动态性要求
  • 项目依赖
  • 特定功能需求(如自定义序列化)

在实际应用中,建议根据具体场景选择最合适的方法,并进行必要的性能测试和优化。对于大多数简单场景,反射或LINQ方法可能是最佳选择;而对于复杂对象或需要特殊处理的情况,JSON序列化方法或ExpandoObject可能更为合适。

无论选择哪种方法,都要注意处理潜在的异常情况,如空值、循环引用等,以确保代码的健壮性和可靠性。

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!