2017-11-27 6 views
0

다음 코드를 고려 상속을 처리 할 수 ​​있어야합니다 :무시 asp.net 코어 Newtonsoft.Json는

내가 상속 클래스를 처리 디시리얼라이저 방법과 과정에 내 자신의 논리를 주입 할 필요가
static void Main(string[] args) 
    { 
     var classes = new Classes() 
     { 
      Instances = new A[]{ 
       new B 
       { 
        BirthDate = DateTime.Now, 
        Name = "B1", 
        SomethingElse = "Test" 
       }, 
       new C 
       { 
        Name = "C1", 
        SomethingElse1 = "Test2", 
        SomethingElse2 = "Test3", 
       } 
      } 
     }; 
     var serialized = JsonConvert.SerializeObject(classes); 
     var deserialized = JsonConvert.DeserializeObject<Classes>(serialized); 
    } 
} 

public class Classes 
{ 
    public A[] Instances { get; set; } 
} 

public enum ClassType 
{ 
    B = 1, 
    C = 2 
} 

public class A 
{ 
    public string Name { get; set; } 
    public virtual ClassType ClassType { get; } 
} 

public class B : A 
{ 
    public string SomethingElse { get; set; } 
    public DateTime BirthDate { get; set; } 
    public override ClassType ClassType => ClassType.B; 

} 

public class C : A 
{ 
    public string SomethingElse1 { get; set; } 
    public string SomethingElse2 { get; set; } 
    public override ClassType ClassType => ClassType.C; 
} 

. 이 경우 JSON의 ClassType 속성을 기반으로 결정을 내리고 싶습니다. 어떤 아이디어/힌트 그것을하는 방법?

BTW. newtonsoft.json TypeNameHandling = TypeNameHandling.All의 기능을 사용할 수 있지만 데이터가 타사 시스템에서 전송되므로 직렬화 프로세스를 제어 할 수는 없습니다. 내가 제어 할 수있는 유일한 것은 역 직렬화 부분입니다.

+0

그것은 – DavidG

답변

1

TypeNameHandling을 사용할 수 없으므로 먼저 구문 분석하고 형식을 찾은 다음 deserialize해야합니다. 그래서 같이

:

var jObj = Newtonsoft.Json.Linq.JObject.Parse(serialized); 

var instances = jObj["Instances"].AsJEnumerable(); 
var myCol = new List<A>(); 
myCol.AddRange(instances.Select(x => (x["ClassType"] as JToken) 
.ToObject<ClassType>() == ClassType.B ? 
    (x as JObject).ToObject<B>() : 
    (x as JObject).ToObject<C>()); 
+0

인가 사용자 정의 변환 https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm를 작성하는 꽤 쉽게 ReadJson 메서드의 구현? – Maris

+0

@Maris 개인적으로 나는 변환기에 신경 쓰지 않겠지 만, 코드를 어떻게 구성 하느냐에 달려있다. 보시다시피, 당신은'ReadJson'에서 그것을 사용했습니다. – zaitsman

0

덕분에 @zaitsman하고 @DavidG 나는 온 업 나를 위해 작동 솔루션. 여기있다 :

public class AClassConverter : JsonConverter 
{ 
    private readonly Type[] _types; 

    public AClassConverter(params Type[] types) 
    { 
     _types = types; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, 
     JsonSerializer serializer) 
    { 
     var jObj = JObject.Load(reader); 
     var classType = jObj["ClassType"].ToObject<ClassType>(); 
     return classType == ClassType.B ? 
      (A)jObj.ToObject<B>() : 
      (A)jObj.ToObject<C>(); 
    } 

    public override bool CanRead => true; 

    public override bool CanWrite => false; 

    public override bool CanConvert(Type objectType) 
    { 
     return _types.Any(t => t == objectType); 
    } 
} 

하고있는 동안

역 직렬화 :

var deserialized = JsonConvert.DeserializeObject<Classes>(serialized, new AClassConverter(typeof(A))); 
+0

그냥'ReadAsInt32'가 실패 할 수도 있습니다 -> 당신이 제공 한 모델을 실제로 다루는 것이라면, enum은'string'과'int'로 직렬화 될 수 있습니다. 솔루션 (내가 C# 대화 형 창에서 노력) 그걸로 제공했다. – zaitsman

+0

@zaitsman, 흠, 네 말이 맞아. 고칠거야, 고마워! – Maris