当前位置: 首页 > news >正文

C# System.Text.Json 中 JsonNamingPolicy 使用详解

总目录


一、JsonNamingPolicy 是什么?

1. 定义

JsonNamingPolicySystem.Text.Json 中用于 控制属性名称在序列化/反序列化时的命名格式的策略类。它允许开发者将 .NET 对象的属性名称转换为指定的格式(如 camelCasesnake_case 等),或自定义其他命名规则。

JsonNamingPolicy 是 System.Text.Json 命名空间中的一个类,用于定义如何在序列化和反序列化过程中处理属性名称与 JSON 字段名称之间的映射关系。

  • 通过使用 JsonNamingPolicy,开发者可以自定义 JSON 字段的命名约定,例如将 C# 中的驼峰命名约定转换为 JSON 中的蛇形命名约定,或者反之。
  • JsonNamingPolicy 通过重写 ConvertName 方法来实现名称转换逻辑。在序列化过程中,ConvertName 方法接收 C# 属性名称并返回 JSON 字段名称;在反序列化过程中,它接收 JSON 字段名称并返回 C# 属性名称。这种双向映射机制确保了在序列化和反序列化过程中名称转换的一致性。

2. 核心作用

  • 序列化时:将 C# 属性名转换为指定格式(如 PascalCasecamelCase)。
  • 反序列化时:将 JSON 中的键名转换为对象的属性名。
  • 命名优先级:显式标记 [JsonPropertyName] 的属性优先级高于命名策略。

3. 适用场景

JsonNamingPolicy 是 System.Text.Json 中 控制属性名称格式的核心工具,适用于以下场景:

  • 适配前后端命名规范(如 C# 的 PascalCase 转为前端的 camelCase)。
  • 统一 API 接口的键名格式(如 snake_case)。
  • 自定义特殊命名规则(如添加前缀/后缀)。

通过内置策略或自定义实现,开发者可以灵活控制 JSON 的属性名称,确保与外部系统的兼容性及代码的可维护性。

二、内置命名策略

System.Text.Json 提供了多种内置命名策略,以满足不同的命名约定需求:

1. 默认策略

默认情况下,无策略(null) ,即保留原始属性名(如 UserNameUserName)。

不过通常在 C# 中 属性会遵守PascalCase 命名策略

public class User
{
    public string UserName { get; set; }
    public int UserAge { get; set; }
}
class Program
{
    static void Main()
    {
        var user = new User { UserName = "John", UserAge = 15 };
        
        // 序列化
        string json = JsonSerializer.Serialize(user);
        Console.WriteLine(json);
        // 输出:{"UserName":"John","UserAge":15}

        // 反序列化
        string jsonString = """{"UserName":"John","UserAge":15}""";
        var u= JsonSerializer.Deserialize<User>(jsonString);
        Console.WriteLine($"UserName = {u.UserName} ,UserAge = {u.UserAge}");
        // 输出:UserName = John ,UserAge = 15
    }
}

2. CamelCase

JsonNamingPolicy.CamelCase 策略将 PascalCase 的 C# 属性名称转换为 camelCase 的 JSON 字段名称。例如,PublicProperty 将被转换为 “publicProperty”。

public class User
{
    public string UserName { get; set; }
    public int UserAge { get; set; }
}
class Program
{
    static void Main()
    {
        var user = new User { UserName = "John", UserAge = 15 };

        var options = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        };
        // 序列化
        string json = JsonSerializer.Serialize(user,options);
        Console.WriteLine(json);
        // 输出:{"userName":"John","userAge":15}

        // 反序列化
        string jsonString = """{"userName":"John","userAge":15}""";
        var u= JsonSerializer.Deserialize<User>(jsonString);
        Console.WriteLine($"UserName = {u.UserName} ,UserAge = {u.UserAge}");
        // 输出:UserName =  ,UserAge = 0

        var u2 = JsonSerializer.Deserialize<User>(jsonString,options);
        Console.WriteLine($"UserName = {u2.UserName} ,UserAge = {u2.UserAge}");
        // 输出:UserName = John ,UserAge = 15
    }
}

注意:序列化和反序列化的时候需要保持使用一致的命名策略,否则就会出现如上案例所示的问题

3. SnakeCaseLower/SnakeCaseUpper

  • JsonNamingPolicy.SnakeCaseLower 策略将 PascalCase 的 C# 属性名称转换为 snake_case 的 JSON 字段名称,并且字段名称为小写。例如,PublicProperty 将被转换为 “public_property”。
  • JsonNamingPolicy.SnakeCaseUpper 策略将 PascalCase 的 C# 属性名称转换为 SNAKE_CASE 的 JSON 字段名称,并且字段名称为大写。例如,PublicProperty 将被转换为 “PUBLIC_PROPERTY”。
public class User
{
    public string UserName { get; set; }
    public int UserAge { get; set; }
}
class Program
{
    static void Main()
    {
        var user = new User { UserName = "John", UserAge = 15 };

        var options = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseUpper
        };

        var options2 = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
        };

        // 序列化
        string json = JsonSerializer.Serialize(user,options);
        Console.WriteLine(json);
        // 输出:{"USER_NAME":"John","USER_AGE":15}

        json = JsonSerializer.Serialize(user, options2);
        Console.WriteLine(json);
        // 输出:{"user_name":"John","user_age":15}


        // 反序列化
        string jsonString = """{"USER_NAME":"John","USER_AGE":15}""";
        var u= JsonSerializer.Deserialize<User>(jsonString,options);
        Console.WriteLine($"UserName = {u.UserName} ,UserAge = {u.UserAge}");
        // 输出:UserName = John ,UserAge = 15
    }
}

4. KebabCaseUpper/KebabCaseLower

  • JsonNamingPolicy.KebabCaseLower 策略将 PascalCase 的 C# 属性名称转换为 kebab-case 的 JSON 字段名称,并且字段名称为小写。例如,UserName 将被转换为 “user-name”。
  • JsonNamingPolicy.KebabCaseUpper 策略将 PascalCase 的 C# 属性名称转换为 KEBAB_CASE 的 JSON 字段名称,并且字段名称为大写。例如,UserName 将被转换为 “USER-NAME”。
public class User
{
    public string UserName { get; set; }
    public int UserAge { get; set; }
}
class Program
{
    static void Main()
    {
        var user = new User { UserName = "John", UserAge = 15 };

        var options = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.KebabCaseUpper
        };

        var options2 = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower
        };

        // 序列化
        string json = JsonSerializer.Serialize(user,options);
        Console.WriteLine(json);
        // 输出:{"USER-NAME":"John","USER-AGE":15}

        json = JsonSerializer.Serialize(user, options2);
        Console.WriteLine(json);
        // 输出:{"user-name":"John","user-age":15}


        // 反序列化
        string jsonString = """{"USER-NAME":"John","USER-AGE":15}""";
        var u= JsonSerializer.Deserialize<User>(jsonString,options);
        Console.WriteLine($"UserName = {u.UserName} ,UserAge = {u.UserAge}");
        // 输出:UserName = John ,UserAge = 15
    }
}

5. 示例:内置策略与 WriteIndented 配合使用

JsonNamingPolicy 不仅可以处理简单的对象,还可以处理包含嵌套对象和集合的复杂对象图。命名策略会递归地应用于对象图中的所有对象。

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Address Address { get; set; }
}
public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public List<PhoneNumber> PhoneNumbers { get; set; }
}
public class PhoneNumber
{
    public string Type { get; set; }
    public string Number { get; set; }
}
var person = new Person
{
    FirstName = "John",
    LastName = "Doe",
    Address = new Address
    {
        Street = "123 Main St",
        City = "New York",
        PhoneNumbers = new List<PhoneNumber>
        {
            new PhoneNumber { Type = "home", Number = "555-1234" },
            new PhoneNumber { Type = "work", Number = "555-5678" }
        }
    }
};
var options = new JsonSerializerOptions
{
    NamingPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true
};
string json = JsonSerializer.Serialize(person, options);
// 输出:
//{
//  "firstName": "John",
//  "lastName": "Doe",
//  "address": {
//    "street": "123 Main St",
//    "city": "New York",
//    "phoneNumbers": [
//      {
//        "type": "home",
//        "number": "555-1234"
//      },
//      {
//        "type": "work",
//        "number": "555-5678"
//      }
//    ]
//  }
//}

三、自定义命名策略

除了内置的命名策略外,System.Text.Json 还允许开发者创建自定义的命名策略,以满足特定的命名转换需求。要创建自定义命名策略,需要创建一个继承自 JsonNamingPolicy 的类,并重写 ConvertName 方法。

1. 创建并使用自定义命名策略

1)创建自定义命名策略

通过继承 JsonNamingPolicy 并重写 ConvertName 方法,可以实现自定义的命名规则。

public class AllUppercaseNamingPolicy : JsonNamingPolicy
{
    public override string ConvertName(string name)
    {
        return name.ToUpper();
    }
}

在上述示例中,AllUppercaseNamingPolicy 类将所有属性名称转换为全大写。

2)使用自定义命名策略

要使用这个自定义策略,可以将其配置到 JsonSerializerOptions 中:

public class User
{
    public string UserName { get; set; }
    public int UserAge { get; set; }
}
class Program
{
    static void Main()
    {
        var user = new User { UserName = "John", UserAge = 15 };

        var options = new JsonSerializerOptions
        {
            PropertyNamingPolicy = new AllUppercaseNamingPolicy()
        };

        // 序列化
        string json = JsonSerializer.Serialize(user,options);
        Console.WriteLine(json);
        // 输出:{"USERNAME":"John","USERAGE":15}

        // 反序列化
        string jsonString = """{"USERNAME":"John","USERAGE":15}""";
        var u= JsonSerializer.Deserialize<User>(jsonString,options);
        Console.WriteLine($"UserName = {u.UserName} ,UserAge = {u.UserAge}");
        // 输出:UserName = John ,UserAge = 15
    }
}

2. 自定义命名策略处理命名冲突

在某些情况下,JSON 字段名称可能与 C# 属性名称不匹配,或者存在命名冲突。通过创建自定义的命名策略,可以解决这些问题。

public class CustomNamingPolicy : JsonNamingPolicy
{
    public override string ConvertName(string name)
    {
        // 处理特定的命名转换
        if (name == "CreatedDate")
            return "created_at";
        
        // 对于其他属性,使用默认的 PascalCase 到 snake_case 转换
        return name.Replace(" ", "_").ToLower();
    }
}

四、字典键的命名策略(DictionaryKeyPolicy

通过 JsonSerializerOptions.DictionaryKeyPolicy,可以控制 字典键名的格式
示例:字典键转为驼峰命名

class Program
{
    static void Main()
    {
        var dictionary = new Dictionary<string, string>
        {
            ["UserName"] = "John",
            ["UserPwd"] = "123"
        };

        var options = new JsonSerializerOptions
        {
            DictionaryKeyPolicy = JsonNamingPolicy.CamelCase // 字典键转为 camelCase
        };

        string json = JsonSerializer.Serialize(dictionary, options);
        Console.WriteLine(json); //输出:{"userName":"John","userPwd":"123"}

        var options2 = new JsonSerializerOptions
        {
            DictionaryKeyPolicy = new CustomCamelCasePolicy()
        };
        json = JsonSerializer.Serialize(dictionary, options2);
        Console.WriteLine(json); //输出:{"userName":"John","userPwd":"123"}
    }
}

public class CustomCamelCasePolicy : JsonNamingPolicy
{
    public override string ConvertName(string name)
    {
        return  char.ToLower(name[0]) + name.Substring(1);
    }
}

五、与 JsonPropertyName 特性结合

JsonPropertyNameAttribute 的优先级高于 JsonNamingPolicy,可覆盖命名策略。

public class Product
{
    [JsonPropertyName("product_id")] // 显式指定名称
    public int Id { get; set; }
    public string Name { get; set; } // 使用命名策略
}

var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};

var product = new Product { Id = 1, Name = "Laptop" };
string json = JsonSerializer.Serialize(product, options);
// 输出:{"product_id":1,"name":"Laptop"}(Name 转为 name)

六、命名策略的注意事项

在使用 JsonNamingPolicy 时,需要注意以下几点:

  1. 策略一致性:在序列化和反序列化过程中,应使用相同的命名策略,以确保名称映射的一致性。

    // 序列化时使用驼峰命名
    var serializedJson = JsonSerializer.Serialize(user, options); // 输出 {"userName":"Alice"}
    
    // 反序列化时需使用相同策略
    var deserializedUser = JsonSerializer.Deserialize<User>(serializedJson, options);
    // 成功匹配属性
    
  2. 性能考虑:使用命名策略可能会对性能产生轻微的影响,因为需要进行额外的字符串转换操作。对于性能敏感的应用

    • 可以考虑优化名称转换逻辑。
    • 避免频繁创建 JsonSerializerOptions:如果命名策略是固定的,可以创建一个静态的 JsonSerializerOptions 实例,并在应用程序中复用它。
  3. 忽略大小写:默认情况下,System.Text.Json 在反序列化过程中是大小写敏感的。如果需要进行大小写不敏感的匹配,可以设置 PropertyNameCaseInsensitive 选项为 true

    var options = new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true
    };
    

结语

回到目录页:C#/.NET 知识汇总
希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。


参考资料:

  • .NET 官方文档:JsonNamingPolicy
  • System.Text.Json 完全指南

相关文章:

  • 四川自助seo建站百度提交入口网址
  • 免费php域名网站宁波企业网站seo
  • 社交博客网站开发怎样进行seo优化
  • 修改网站图片一网信息一个简单便捷的新闻网站
  • 嘉兴网站排名公司一个好的产品怎么推广
  • 那些网站可以做团购绍兴百度seo排名
  • ue5 仿鬼泣5魂类游戏角色和敌人没有碰撞
  • Opencv计算机视觉编程攻略-第八节 检测兴趣点
  • linux 安装 mysql记录
  • 【机器学习中的基本术语:特征、样本、训练集、测试集、监督/无监督学习】
  • SpringKafka错误处理:重试机制与死信队列
  • WPF设计学习记录滴滴滴4
  • 安装 Microsoft Visual C++ Build Tools
  • 测风塔选址和安装原则
  • Nginx的URL重写及访问控制
  • AI智能体驱动下的营销范式革命:解码“氛围营销“时代的战略重构
  • 《Linux内存管理:实验驱动的深度探索》【附录】【实验环境搭建 2】【vscode搭建调试内核环境】
  • Gemini 2.5 Pro与Claude 3.7 Sonnet编程性能对比
  • UE5学习笔记 FPS游戏制作38 继承标准UI
  • 如何本地部署DeepSeek:从零实现AI模型私有化部署
  • 【Java SE】Math类、System类
  • 【Ragflow】10. 助理配置参数详细解析/模型响应加速方法
  • 开源的 LLM 应用开发平台Dify的安装和使用
  • SQL 查询执行顺序
  • js逆向入门图灵爬虫练习平台 第四题学习
  • Java 二叉树非递归遍历核心实现