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
相关产品推荐
相关产品推荐

