如何将JSON反序列化为使用组合的C#类
我需要反序列化如何将JSON反序列化为使用组合的C#类,c#,json,serialization,C#,Json,Serialization,我需要反序列化 {'Id':'id123', “时间”:143621503, 'Name':'foo', “ProductId”:1} 装入集装箱1 public class Container1 { public CommonFields Common { get; set; } //fields specific to Container1 [JsonProperty(PropertyName = "Name")] public string Name {
{'Id':'id123',
“时间”:143621503,
'Name':'foo',
“ProductId”:1}
装入集装箱1
public class Container1
{
public CommonFields Common { get; set; }
//fields specific to Container1
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "ProductId")]
public int ProductId { get; set; }
}
及
{
“Id”:“id123”,
“时间”:143621503,
“组”:“10768C21-9971-4D2F-ACD7-10C2EF19FCA8”
}
装入集装箱2
public class Container2
{
public CommonFields Common { get; set; }
//fields specific to Container2
[JsonProperty(PropertyName = "Group")]
public Guid Group { get; set; }
}
使用组合(而不是继承)。两个JSON都有两个公共字段(Id和时间)和特定字段
使用newtonsoft.json
JsonConvert.DeserializeObject(json\u container1)
结果是2容器的属性被正确反序列化。组合类的公共属性未反序列化
如何将JSON反序列化为只使用组合的C#类?
(不强制使用newtonsoft.json)
下面是我的尝试
public class CommonFields
{
[JsonProperty(PropertyName = "Id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "Time")]
public long Time { get; set; }
}
public class Container1
{
public CommonFields Common { get; set; }
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "ProductId")]
public int ProductId { get; set; }
}
public class Container2
{
public CommonFields Common { get; set; }
[JsonProperty(PropertyName = "Group")]
public Guid Group { get; set; }
}
internal class Program
{
private static void Main(string[] args)
{
string json_container1 = @"{
'Id': 'id123',
'Time': 1436231503,
'Name': 'foo',
'ProductId': 1
}";
string json_container2 = @"{
'Id': 'id123',
'Time': 1436231503,
'Group':'10768C21-9971-4D2F-ACD7-10C2EF19FCA8'
}";
var container1Obj = JsonConvert.DeserializeObject<Container1>(json_container1);
var container2Obj = JsonConvert.DeserializeObject<Container2>(json_container2);
Console.ReadKey();
}}}
公共类公共字段
{
[JsonProperty(PropertyName=“Id”)]
公共字符串Id{get;set;}
[JsonProperty(PropertyName=“Time”)]
公共长时间{get;set;}
}
公共类集装箱1
{
公共公共字段公共{get;set;}
[JsonProperty(PropertyName=“Name”)]
公共字符串名称{get;set;}
[JsonProperty(PropertyName=“ProductId”)]
public int ProductId{get;set;}
}
公共类集装箱2
{
公共公共字段公共{get;set;}
[JsonProperty(PropertyName=“Group”)]
公共Guid组{get;set;}
}
内部课程计划
{
私有静态void Main(字符串[]args)
{
字符串json_container1=@”{
“Id”:“id123”,
“时间”:143621503,
'Name':'foo',
“ProductId”:1
}";
字符串json_container2=@”{
“Id”:“id123”,
“时间”:143621503,
“组”:“10768C21-9971-4D2F-ACD7-10C2EF19FCA8”
}";
var container1Obj=JsonConvert.DeserializeObject(json_container1);
var container2Obj=JsonConvert.DeserializeObject(json_container2);
Console.ReadKey();
}}}
不要这样做。
从中反序列化的JSON元素不应更改,您可以删除一些属性,但更改其属性结构是一种不好的做法
JSON file\content应该有一个兼容的JSON类,如果您想进行任何更改,请创建另一个自定义类,并在它们之间创建映射逻辑。我认为您可以仅在两个对象的公共字段上再次进行反序列化
container1Obj.Common = JsonConvert.DeserializeObject<CommonFields>(json_container1);
container2Obj.Common = JsonConvert.DeserializeObject<CommonFields>(json_container2);
container1Obj.Common=JsonConvert.DeserializeObject(json_container1);
container2Obj.Common=JsonConvert.DeserializeObject(json_container2);
我知道你想使用组合,但我真的看不出在这里使用组合而不是继承有什么好处
public class BaseClass
{
[JsonProperty(PropertyName = "Id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "Time")]
public long Time { get; set; }
}
public class Container1 : BaseClass
{
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "ProductId")]
public int ProductId { get; set; }
}
public class Container2 : BaseClass
{
[JsonProperty(PropertyName = "Group")]
public Guid Group { get; set; }
}
这很简单,应该能完成任务。你的问题基本上与问题相反,可以用类似的策略解决。为了简化操作,请为包含公共字段的所有类创建一个接口:
public interface IHasCommonFields
{
CommonFields Common { get; set; }
}
然后,您可以为实现此接口的任何类型创建以下通用转换器:
public class HasCommonFieldsConverter<T> : JsonConverter where T : IHasCommonFields
{
[ThreadStatic]
static bool disabled;
// Disables the converter in a thread-safe manner.
bool Disabled { get { return disabled; } set { disabled = value; } }
public override bool CanWrite { get { return !Disabled; } }
public override bool CanRead { get { return !Disabled; } }
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var token = JToken.Load(reader);
if (token == null || token.Type == JTokenType.Null)
return null;
using (new PushValue<bool>(true, () => Disabled, val => Disabled = val)) // Prevent infinite recursion of converters
{
var hasCommon = token.ToObject<T>(serializer);
var common = (hasCommon.Common ?? (hasCommon.Common = new CommonFields()));
serializer.Populate(token.CreateReader(), common);
return hasCommon;
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
writer.WriteNull();
return;
}
using (new PushValue<bool>(true, () => Disabled, val => Disabled = val)) // Prevent infinite recursion of converters
{
var hasCommon = (T)value;
var obj = JObject.FromObject(hasCommon, serializer);
var common = hasCommon.Common;
if (common != null)
{
var commonObj = JObject.FromObject(common, serializer);
obj.Merge(commonObj);
}
obj.WriteTo(writer);
}
}
}
public struct PushValue<T> : IDisposable
{
Action<T> setValue;
T oldValue;
public PushValue(T value, Func<T> getValue, Action<T> setValue)
{
if (getValue == null || setValue == null)
throw new ArgumentNullException();
this.setValue = setValue;
this.oldValue = getValue();
setValue(value);
}
#region IDisposable Members
// By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
public void Dispose()
{
if (setValue != null)
setValue(oldValue);
}
#endregion
}
然后,要测试:
public class TestClass
{
public static void Test()
{
var container1 = new Container1 { Name = "name", ProductId = 101, Common = new CommonFields { Id = "1401", Time = DateTime.Today.Ticks } };
var container2 = new Container2 { Group = Guid.NewGuid(), Common = new CommonFields { Id = "2401", Time = DateTime.Today.Ticks } };
Test(container1);
Test(container2);
}
private static void Test<T>(T container) where T : class, IHasCommonFields
{
var json = JsonConvert.SerializeObject(container, Formatting.Indented);
Debug.WriteLine(json);
var containerback = JsonConvert.DeserializeObject<T>(json);
var json2 = JsonConvert.SerializeObject(containerback, Formatting.Indented);
Debug.Assert(json == json2); // No assert
if (container.Common != null)
{
Debug.Assert(container.Common.Id == containerback.Common.Id); // No assert
Debug.Assert(container.Common.Time == containerback.Common.Time); // No assert
}
}
}
及
此转换器的一个缺点是,如果序列化时Common
属性为null,则将使用默认值反序列化为非null
如果您不想使用IHasCommonFields
接口,例如,您可以使用抽象方法为转换器创建一个抽象泛型基类,以获取和设置公共字段,然后在每个子类中重写这些方法
(老实说,这里的继承似乎比组合更简单,正如其他答案所述。)为什么要首先避免使用继承?您可以有一个包含公共字段的基类和从中继承的两个子类。
public class TestClass
{
public static void Test()
{
var container1 = new Container1 { Name = "name", ProductId = 101, Common = new CommonFields { Id = "1401", Time = DateTime.Today.Ticks } };
var container2 = new Container2 { Group = Guid.NewGuid(), Common = new CommonFields { Id = "2401", Time = DateTime.Today.Ticks } };
Test(container1);
Test(container2);
}
private static void Test<T>(T container) where T : class, IHasCommonFields
{
var json = JsonConvert.SerializeObject(container, Formatting.Indented);
Debug.WriteLine(json);
var containerback = JsonConvert.DeserializeObject<T>(json);
var json2 = JsonConvert.SerializeObject(containerback, Formatting.Indented);
Debug.Assert(json == json2); // No assert
if (container.Common != null)
{
Debug.Assert(container.Common.Id == containerback.Common.Id); // No assert
Debug.Assert(container.Common.Time == containerback.Common.Time); // No assert
}
}
}
{
"Name": "name",
"ProductId": 101,
"Id": "1401",
"Time": 635725152000000000
}
{
"Group": "9ed31118-c0b7-4d9f-8f57-303b2e164643",
"Id": "2401",
"Time": 635725152000000000
}