2016-09-01 8 views
-1

serialiseするとき、私はClassNameを_CurrentClassNameプロパティにオブジェクトに書き込みます。 JSON.Netライブラリでjsonを読むとき、このプロパティからオブジェクトを値に変更する必要があります。オブジェクト型が推測されており、オブジェクトがインスタンス化された後JSON.Netでデシリアライズするとき、またはデフォルトのシリアライザを呼び出すときに、オブジェクトタイプを別のものに変更する方法はありますか?

{ 
"Field1": 0, 
"Field2": "34", 
"_CurrentClassName": "MyCustomClass" 
} 


class CustomJsonConverter : JsonConverter 
{ 
... 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType.IsClass; 
    } 
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var value = existingValue; 
     if (reader.TokenType == JsonToken.Null) 
     { 
      return null; 
     } 
     else if (reader.TokenType == JsonToken.StartObject) 
     { 
      JObject jObject = JObject.Load(reader); 
      JToken jToken; 
      if (jObject.TryGetValue("_CurrentClassName", out jToken)) 
      { 
       var t = jToken.Value<string>(); 
       Type tt = Type.GetType(objectType.Namespace + "." + t); 
       value = Activator.CreateInstance(tt); 
       return value; 
      } 
     } 
     return serializer.Deserialize(reader);    
    } 

... 
} 
+0

[Json.Net多型子オブジェクトの型のシリアル化](https://stackoverflow.com/questions/29528648/json-net-serialization-of-type)の回答と同様のことができます - 多型子オブジェクトあり/ 29531372#29531372)。 – dbc

+0

ありがとうございます。同様に、私は "ハード"タイプを使用することはできません、私のCanConvertは次のようになります: public override bool CanConvert(type objectType) { return objectType.IsClass; } – ndbnndbn

+0

あなたはそのプロパティ名と構文に結婚しているのですか、これを処理するためにJson.Netを使用するだけですか? –

答えて

0

、あなたはそれを埋めるためにJsonSerializer.Populate(jObject.CreateReader())を使用することができます。例えば

public abstract class CustomJsonConverterBase : JsonConverter 
{ 
    protected abstract Type InferType(JToken token, Type objectType, object existingValue); 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 
     var token = JToken.Load(reader); 
     var actualType = InferType(token, objectType, existingValue); 
     if (existingValue == null || existingValue.GetType() != actualType) 
     { 
      var contract = serializer.ContractResolver.ResolveContract(actualType); 
      existingValue = contract.DefaultCreator(); 
     } 
     using (var subReader = token.CreateReader()) 
     { 
      // Using "populate" avoids infinite recursion. 
      serializer.Populate(subReader, existingValue); 
     } 
     return existingValue; 
    } 

    public override bool CanWrite { get { return false; } } 

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

public class CustomJsonConverter : CustomJsonConverterBase 
{ 
    public const string ClassPropertyName = @"_CurrentClassName"; 

    protected override Type InferType(JToken token, Type objectType, object existingValue) 
    { 
     if (token is JObject) 
     { 
      var typeName = (string)token[ClassPropertyName]; 
      if (typeName != null) 
      { 
       var actualType = Type.GetType(objectType.Namespace + "." + typeName); 
       if (actualType != null) 
        return actualType; 
      } 
     } 
     return objectType; 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     throw new NotImplementedException(); 
    } 
} 

CustomCreationConverter<T>もわずかに割り当てられたオブジェクトを埋めるserializer.Populate()を使用するので、これはこの問題を解決するための標準的な方法です。

Json.NETに組み込まれているTypeNameHandling機能の一部を複製していることに注意してください。

+0

ありがとう、私はこれを理解して使用しようとします。 – ndbnndbn

+0

フィルタシステムタイプの操作。ありがとうございました! public override bool CanConvert(ObjectType型) { //新しいNotImplementedException()をスローします。 return objectType.IsClass && objectType.Namespace!= null &&!objectType.Namespace.StartsWith( "System"); } – ndbnndbn

0

_CurrentClassNameプロパティ名またはその値構文と結婚していない場合は、Json.Netの組み込み型の処理を使用できます。

シリアライズまたはデシリアライズするときに、シリアライゼーションまたはデシリアライゼーションを制御するオブジェクトJsonSerializerSettingsを渡すことができます。

このオブジェクトでは、処理される正確なタイプをJson.Netでシリアル化およびデシリアライズする方法を制御するTypeNameHandlingプロパティを設定できます。ここで

LINQPad例です。

void Main() 
{ 
    var t = new Test { Key = 42, Value = "Meaning of life" }; 

    var json = JsonConvert.SerializeObject(
     t, Newtonsoft.Json.Formatting.Indented, 
     new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }); 
    Console.WriteLine(json); 

    var obj =JsonConvert.DeserializeObject(json, 
     new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }); 
    Console.WriteLine(obj.GetType().FullName); 
} 

public class Test 
{ 
    public int Key { get; set; } 
    public string Value { get; set; } 
} 

は出力:ここ

{ 
    "$type": "UserQuery+Test, LINQPadQuery", 
    "Key": 42, 
    "Value": "Meaning of life" 
} 
UserQuery+Test 

あなたは、デシリアライゼーションから返されるオブジェクトの型がTestクラスであることがわかります。

+0

結婚しました。 typenameにC#名前空間を使用できない – ndbnndbn

関連する問題