我有以下课程:
public class MyRequest
{
public string Type {get;set;}
public string Source {get;set;}
}
我想从名为Source
的值的JSON字段序列化/反序列化Type
的值,例如:
{
"type": "bank",
"bank": "Some value"
}
或
{
"type": "card",
"card": "Some value"
}
两者都绑定到Source
属性。
答案 0 :(得分:1)
您可以创建自定义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
答案 1 :(得分:1)
我最近遇到了这种问题,我需要使用具有动态数据契约的 API,因此我开发了一个名为 SerializationInterceptor 的包。这是 GitHub 链接:https://github.com/Dorin-Mocan/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;
}
}
然后将拦截器放在 Source 道具上:
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);
});
答案 2 :(得分:0)
我会编写自定义序列化/反序列化方法
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>();
}
答案 3 :(得分:0)
我的解决方案是: 首先创建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