使用 JSON.NET 序列化/反序列化动态属性名称



我有以下类:

public class MyRequest
{
    public string Type {get;set;}
    public string Source {get;set;}
}

我想序列化/反序列化名为 Type 值的 JSON 字段中的Source值,例如:

{
    "type": "bank",
    "bank": "Some value"
}

{
    "type": "card",
    "card": "Some value"
}

两者绑定到Source属性的位置。

您可以创建自定义JsonConverter来处理动态属性名称:

public class MyRequestConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(MyRequest);
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        string type = (string)jo["type"];
        MyRequest req = new MyRequest
        {
            Type = type,
            Source = (string)jo[type ?? ""]
        };
        return req;
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        MyRequest req = (MyRequest)value;
        JObject jo = new JObject(
            new JProperty("type", req.Type),
            new JProperty(req.Type, req.Source));
        jo.WriteTo(writer);
    }
}

若要使用转换器,请向类添加 [JsonConverter] 属性,如下所示:

[JsonConverter(typeof(MyRequestConverter))]
public class MyRequest
{
    public string Type { get; set; }
    public string Source { get; set; }
}

这是一个有效的往返演示:https://dotnetfiddle.net/o7NDTV

我会编写自定义序列化/反序列化方法

var req1 = new MyRequest() { Type = "card", Source = "SomeValue" };
var json = Serialize(req1);
var req2 = Deserialize<MyRequest>(json);

string Serialize<T>(T obj)
{
    var jObj = JObject.FromObject(obj);
    var src = jObj["Source"];
    jObj.Remove("Source");
    jObj[(string)jObj["Type"]] = src;
    return jObj.ToString(Newtonsoft.Json.Formatting.Indented);
}
T Deserialize<T>(string json)
{
    var jObj = JObject.Parse(json);
    var src = jObj[(string)jObj["Type"]];
    jObj.Remove((string)jObj["Type"]);
    jObj["Source"] = src;
    return jObj.ToObject<T>();
} 

我最近遇到了这种问题,我需要使用具有动态数据协定的API,所以我开发了一个名为SerializationInterceptor的包。这是GitHub链接:https://github.com/essencebit/SerializationInterceptor/wiki。还可以使用 Nuget 包管理器安装包。

下面的示例使用 Newtonsoft.Json 进行序列化/反序列化。当然,您可以使用任何其他工具,因为此软件包不依赖于任何工具。

您可以做的是创建一个拦截器:

public class JsonPropertyInterceptorAttribute : SerializationInterceptor.Attributes.InterceptorAttribute
{
    public JsonPropertyInterceptorAttribute(string interceptorId)
        : base(interceptorId, typeof(JsonPropertyAttribute))
    {
    }
    protected override SerializationInterceptor.Attributes.AttributeBuilderParams Intercept(SerializationInterceptor.Attributes.AttributeBuilderParams originalAttributeBuilderParams)
    {
        object value;
        switch (InterceptorId)
        {
            case "some id":
                // For DESERIALIZATION you first need to deserialize the object here having the prop Source unmapped(we'll invoke the proper deserialization later to have Source prop mapped to the correct Json key),
                // then get the value of the prop Type and assign it to variable from below.
                // For SERIALIZATION you need somehow to have here access to the object you want to serialize and get
                // the value of the Type prop and assign it to variable from below.
                value = "the value of Type prop";
                break;
            default:
                return originalAttributeBuilderParams;
        }
        originalAttributeBuilderParams.ConstructorArgs = new[] { value };
        return originalAttributeBuilderParams;
    }
}

然后将拦截器放在源道具上:

public class MyRequest
{
    [JsonProperty("type")]
    public string Type { get; set; }
    [JsonPropertyInterceptor("some id")]
    [JsonProperty("source")]
    public string Source { get; set; }
}

然后调用正确的序列化/反序列化,如下所示:

var serializedObj = SerializationInterceptor.Interceptor.InterceptSerialization(obj, objType, (o, t) =>
{
    var serializer = new JsonSerializer { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
    using var stream = new MemoryStream();
    using var streamWriter = new StreamWriter(stream);
    using var jsonTextWriter = new JsonTextWriter(streamWriter);
    serializer.Serialize(jsonTextWriter, o, t);
    jsonTextWriter.Flush();
    return Encoding.Default.GetString(stream.ToArray());
})
var deserializedObj = SerializationInterceptor.Interceptor.InterceptDeserialization(@string, objType, (s, t) =>
{
    var serializer = new JsonSerializer();
    using var streamReader = new StreamReader(s);
    using var jsonTextReader = new JsonTextReader(streamReader);
    return serializer.Deserialize(jsonTextReader, t);
});

我的解决方案是:首先创建 APIResultModel 类:

public class APIResultModel<T> where T: APIModel, new()
{
    public string ImmutableProperty { get; set; }
    public T Result { get; set; }
    public APIResultModel<T> Deserialize(string json)
    {
        var jObj = JObject.Parse(json);
        T t = new T();
        var result = jObj[t.TypeName()];
        jObj.Remove(t.TypeName());
        jObj["Result"] = result;
        return jObj.ToObject<APIResultModel<T>>();
    }
}

第二个创建 APIModel 抽象类:

public abstract class APIModel
{
    public abstract string TypeName();
}

第三创建动态内容 模型类:

public class MyContentModel: APIModel
{
    public string Property {get; set;}
    public override string TypeName()
    {
        return "JsonKey";
    }
}

当您需要反序列化 json 字符串时:

var jsonModel = new APIResultModel<MyContentModel>();
jsonModel = jsonModel.Deserialize(json);
MyContentModel dynimacModel = jsonModel.Result;

反序列化函数来自@Eser

相关内容

  • 没有找到相关文章

最新更新