You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Json.NET实现序列化与反序列化时类与JSON属性异向映射

用Json.NET实现类属性与JSON属性的异向映射(Firebase Timestamp场景)

嘿,这个需求完全可以通过自定义JsonConverter结合抽象基类来实现,核心思路是在转换器里区分序列化和反序列化的逻辑,分别处理属性的映射方向。下面是针对Firebase SystemTimestamp场景的完整实现方案:

第一步:定义抽象基类

首先创建一个抽象基类,包含两个核心属性:一个用于序列化时生成Firebase的特殊timestamp标记,另一个用于反序列化时接收解析后的时间戳值。所有需要处理Firebase时间的实体类都可以继承这个基类:

[JsonConverter(typeof(FirebaseTimestampConverter))]
public abstract class FirebaseTimestampEntity
{
    // 序列化时:这个属性会被转成JSON的"timestamp"字段(Firebase特殊格式)
    [JsonIgnore] // 避免默认序列化,交给自定义转换器处理
    public virtual DateTimeOffset? SerializeTimestamp { get; set; }

    // 反序列化时:JSON的"timestamp"字段会被解析到这个属性
    [JsonIgnore] // 避免默认反序列化,交给自定义转换器处理
    public virtual DateTimeOffset? DeserializedTimestamp { get; set; }
}

第二步:实现自定义JsonConverter

接下来写一个自定义转换器,在WriteJson方法里处理序列化逻辑(把基类的SerializeTimestamp转成Firebase的特殊"timestamp"字段),在ReadJson方法里处理反序列化逻辑(把JSON的"timestamp"数字解析到DeserializedTimestamp):

public class FirebaseTimestampConverter : JsonConverter<FirebaseTimestampEntity>
{
    public override void WriteJson(JsonWriter writer, FirebaseTimestampEntity value, JsonSerializer serializer)
    {
        // 先序列化实体类的其他属性
        var jo = JObject.FromObject(value, serializer);

        // 如果SerializeTimestamp有值,添加Firebase的特殊timestamp标记
        if (value.SerializeTimestamp.HasValue)
        {
            jo.Add("timestamp", JObject.FromObject(new { ".sv" = "timestamp" }));
        }

        jo.WriteTo(writer);
    }

    public override FirebaseTimestampEntity ReadJson(JsonReader reader, Type objectType, FirebaseTimestampEntity existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var jo = JObject.Load(reader);

        // 先反序列化实体类的其他属性
        var entity = existingValue ?? (FirebaseTimestampEntity)Activator.CreateInstance(objectType);
        serializer.Populate(jo.CreateReader(), entity);

        // 读取JSON中的"timestamp"数字时间戳(毫秒级)并解析到DeserializedTimestamp
        if (jo.TryGetValue("timestamp", out var timestampToken) && timestampToken.Type == JTokenType.Integer)
        {
            var milliseconds = timestampToken.Value<long>();
            entity.DeserializedTimestamp = DateTimeOffset.FromUnixTimeMilliseconds(milliseconds);
        }

        return entity;
    }
}

第三步:使用示例

现在创建一个子类来验证效果:

public class User : FirebaseTimestampEntity
{
    public string Id { get; set; }
    public string Name { get; set; }
}

序列化测试(生成Firebase格式的JSON)

var user = new User
{
    Id = "user123",
    Name = "John Doe",
    SerializeTimestamp = DateTimeOffset.UtcNow // 触发timestamp字段生成
};

var json = JsonConvert.SerializeObject(user, Formatting.Indented);

输出的JSON会包含Firebase的特殊timestamp字段:

{
  "Id": "user123",
  "Name": "John Doe",
  "timestamp": {
    ".sv": "timestamp"
  }
}

反序列化测试(解析Firebase返回的时间戳)

假设从Firebase拿到这样的JSON:

{
  "Id": "user123",
  "Name": "John Doe",
  "timestamp": 1699999999000
}

反序列化代码:

var json = "..."; // 上面的JSON字符串
var user = JsonConvert.DeserializeObject<User>(json);

// 此时user.DeserializedTimestamp会被解析为对应的DateTimeOffset
Console.WriteLine(user.DeserializedTimestamp.Value.ToString("yyyy-MM-dd HH:mm:ss"));

额外说明

  • 如果你的Firebase timestamp是秒级数字,只需把ReadJson里的FromUnixTimeMilliseconds换成FromUnixTimeSeconds即可。
  • 如果需要自定义JSON字段名(不是"timestamp"),可以在基类里加一个抽象属性让子类指定,比如public abstract string TimestampJsonPropertyName { get; },然后在转换器里动态使用这个名称。
  • 如果某些子类不需要这个映射逻辑,可以在子类上标记[JsonConverter(null)]来禁用基类的转换器。

内容的提问来源于stack exchange,提问作者tonsteri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:59:57