C#中Json序列化的进阶用法

本文所有json序列化,都使用的Newtonsoft.Json包

1 JsonIgnore

在 Newtonsoft.Json 中,如果你不想将某些属性转换为 JSON 字符串,可以使用多种方法来实现。以下是几种常见的方法:

1.1 使用 [JsonIgnore] 特性

[JsonIgnore] 特性可以直接忽略某个属性,使其不会被序列化为 JSON。

csharp 复制代码
using Newtonsoft.Json;

public class MyClass
{
    public int Id { get; set; }
    public string Name { get; set; }

    [JsonIgnore]
    public string Password { get; set; }
}

class Program
{
    static void Main()
    {
        var obj = new MyClass { Id = 1, Name = "John", Password = "secret" };
        string json = JsonConvert.SerializeObject(obj);
        Console.WriteLine(json);
    }
}

输出:

json 复制代码
{"Id":1,"Name":"John"}

1.2 使用 [JsonProperty] 特性并设置 DefaultValueHandling

你可以使用 [JsonProperty] 特性并设置 DefaultValueHandlingIgnore,这样当属性的值为默认值时,它不会被序列化为 JSON。

csharp 复制代码
using Newtonsoft.Json;

public class MyClass
{
    public int Id { get; set; }
    public string Name { get; set; }

    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
    public string Password { get; set; }
}

class Program
{
    static void Main()
    {
        var obj = new MyClass { Id = 1, Name = "John", Password = null };
        string json = JsonConvert.SerializeObject(obj);
        Console.WriteLine(json);
    }
}

输出:

json 复制代码
{"Id":1,"Name":"John"}

2 自定义解析方式

在使用 JsonConvert.DeserializeObject 解析 JSON 数据时,如果某个属性需要以特定的方式进行解析,可以通过自定义 JsonConverter 来实现。JsonConverter 允许你定义如何将 JSON 数据转换为 .NET 对象,或者将 .NET 对象转换为 JSON 数据。

以下是一个示例,展示如何为特定属性创建自定义的 JsonConverter

2.1 创建自定义的 JsonConverter

假设你有一个类 MyClass,其中有一个属性 MyProperty,你希望以特定的方式解析这个属性:

csharp 复制代码
public class MyClass
{
    public string MyProperty { get; set; }
}

你可以创建一个自定义的 JsonConverter 来处理 MyProperty

csharp 复制代码
public class MyPropertyConverter : JsonConverter<string>
{
    public override string ReadJson(JsonReader reader, Type objectType, string existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        // 读取 JSON 数据
        var jsonObject = JObject.Load(reader);

        // 自定义解析逻辑
        if (jsonObject["customField"] != null)
        {
            return jsonObject["customField"].ToString();
        }

        return string.Empty;
    }

    public override void WriteJson(JsonWriter writer, string value, JsonSerializer serializer)
    {
        // 自定义序列化逻辑
        writer.WriteValue(value);
    }
}

2.2 在属性上应用自定义的 JsonConverter

你可以在 MyClassMyProperty 属性上使用 [JsonConverter] 特性来指定自定义的 JsonConverter

csharp 复制代码
public class MyClass
{
    [JsonConverter(typeof(MyPropertyConverter))]
    public string MyProperty { get; set; }
}

2.3 使用 JsonConvert.DeserializeObject 进行解析

现在,当你使用 JsonConvert.DeserializeObject 解析 JSON 数据时,MyProperty 属性将按照你定义的自定义逻辑进行解析:

csharp 复制代码
string json = "{ \"MyProperty\": { \"customField\": \"customValue\" } }";
MyClass myObject = JsonConvert.DeserializeObject<MyClass>(json);

Console.WriteLine(myObject.MyProperty);  // 输出: customValue

2.4 总结

通过创建自定义的 JsonConverter 并在属性上应用它,你可以灵活地控制 JSON 数据的解析方式。这种方式适用于需要对特定属性进行特殊处理的场景。

3 进阶用法-动态读取,结合反射解析json

一般来说,添加了引用的内容,Newtonsoft.Json都可以直接解析,包括Type

动态读取的dll,如果放在了和执行文件同一目录下也可以正常解析,但是一旦脱离这个目录,json序列化就不行了,找不到对应的内容,尝试了很多方式都不行,结合第二部分,可以使用反射实现。

这种方式有个前提条件,目标dll需要在执行解析之前被读取,这样读取到的资源会保存到AppDomain.CurrentDomain中去,才能进行解析。

csharp 复制代码
Assembly.LoadFrom(dllFile);
csharp 复制代码
/// <summary>
/// 涉及到Type的序列化
/// 并且插件的程序集是程序显式读取的
/// 默认的解析方式读取不到插件对应的dll
/// 需要做自定义解析
/// </summary>
public class TypeJsonConverter : JsonConverter<Type>
{
    /// <summary>
    /// 自定义该属性的解析方式
    /// </summary>
    public override Type ReadJson(JsonReader reader, Type objectType, Type existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        // 自定义解析逻辑
        if (reader.Value != null)
        {
            //在调用该程序之前,需要确保插件的dll已经被显式读取,也就是已经存在于主程序集的上下文之中
            var typeValue = AppDomain.CurrentDomain
                .GetAssemblies()
                .SelectMany(a => a.GetTypes())
                .Where(plu => plu.AssemblyQualifiedName.Equals(reader.Value))
                .FirstOrDefault();
            return typeValue;
        }

        return null;
    }

    /// <summary>
    /// 自定义该属性的写入方式
    /// </summary>
    public override void WriteJson(JsonWriter writer, Type value, JsonSerializer serializer)
    {
        // 自定义序列化逻辑
        writer.WriteValue(value.AssemblyQualifiedName);
    }
}

然后标记属性

csharp 复制代码
/// <summary>
/// 插件,标记自定义解析方式,否则会解析失败
/// 目前先这样处理
/// </summary>
[JsonConverter(typeof(TypeJsonConverter))]
public Type PluginType { get; set; }
相关推荐
七七&5563 小时前
2024年08月13日 Go生态洞察:Go 1.23 发布与全面深度解读
开发语言·网络·golang
java坤坤4 小时前
GoLand 项目从 0 到 1:第八天 ——GORM 命名策略陷阱与 Go 项目启动慢问题攻坚
开发语言·后端·golang
元清加油4 小时前
【Golang】:函数和包
服务器·开发语言·网络·后端·网络协议·golang
健康平安的活着4 小时前
java之 junit4单元测试Mockito的使用
java·开发语言·单元测试
DjangoJason6 小时前
C++ 仿RabbitMQ实现消息队列项目
开发语言·c++·rabbitmq
m0_480502646 小时前
Rust 入门 KV存储HashMap (十七)
java·开发语言·rust
大阳1236 小时前
线程(基本概念和相关命令)
开发语言·数据结构·经验分享·算法·线程·学习经验
YA3336 小时前
java基础(九)sql基础及索引
java·开发语言·sql
奇树谦7 小时前
QT|windwos桌面端应用程序开发,当连接多个显示器的时候,如何获取屏幕编号?
开发语言·qt
weixin_307779137 小时前
VS Code配置MinGW64编译GNU 科学库 (GSL)
开发语言·c++·vscode·算法