2016-06-29 11 views
6

で定義された別のプロパティ名にJSON文字列とマップのプロパティをデシリアライズまたはシリアライズ:Json.NETは、私は次のようなJSON文字列を持っているランタイム

{ 
    "values": { 
     "details": { 
      "property1": "94", 
      "property2": "47", 
      "property3": "32", 
      "property4": 1 
     }, 
     count: 4 
    } 
}  

私は、次のモデルにこれをマッピングするつもりです:

public class Details 
{ 
    public string property1 { get; set; } 
    public string property2 { get; set; } 
    public string property3 { get; set; } 
    public int property4 { get; set; } 
} 

public class Values 
{ 
    public Details details { get; set; } 
    public int count { get; set; } 
} 

public class RootObject 
{ 
    public Values values { get; set; } 
} 

JsonConvert.DeserializeObject<RootObject>(jsonString); 

は、私はこのような、このJSON文字列をデシリアライズするとき、実行時に別の名前にこれらのプロパティ名をマッピングすることができるようにしたいです

たとえば、逆シリアル化プロセスでは、「property1」の名前を「differen_property_name1」または「differen_property_name2」または「differen_property_name3」にdeserializeします。ここで示唆したように、私は、ランタイム(私は「プロパティ1」の名前を変更する先の新しい名前)で、新しい名前を選択しています ので、私は、JsonPropertyAttributeを用いて溶液を使用することはできません。

.NET NewtonSoft JSON deserialize map to a different property name

上記の質問の答えの1つ(Jackの答え)は、DefaultContractResolverの継承を使用しますが、その場合は機能しないようです。後で

更新

、私は、デシリアライゼーションからもらったオブジェクトをシリアル化し、実行時に定義された異なるプロパティ名にプロパティをマップする必要がありました。 ブライアンシリアル化を行うために提案されたように、私は同じ方法を使用:

私は私の新しいプロパティ名をマッピングするために辞書を使用:

var map = new Dictionary<Type, Dictionary<string, string>> 
{ 
    { 
     typeof(Details), 
     new Dictionary<string, string> 
     { 
      {"property1", "myNewPropertyName1"}, 
      {"property2", "myNewPropertyName2"}, 
      {"property3", "myNewPropertyName3"}, 
      {"property4", "myNewPropertyName4"} 
     } 
    } 
};  

、その後、私はこのようなオブジェクトをシリアル化するためにブライアンのDynamicMappingResolverを使用:

var settings = new JsonSerializerSettings 
{ 
    ContractResolver = new DynamicMappingResolver(map) 
}; 

var root = JsonConvert.SerializeObject(myObjectInstance, settings);    
+0

を私はプロパティに与えたいた新しい名前ランタイムで決定したいとJsonPropertyAttributeであなたが「ハードコード」の名前を使用する必要があるため。 –

+0

片方向(醜いかもしれませんが)は、最初にJSONを逆シリアル化し、逆シリアル化されたオブジェクトを新しい名前のオブジェクトにマップすることです。しかし、よりエレガントな方法があるかもしれません。 – Tim

+0

@Tim、実行時に新しい名前を定義する必要がある場合、どのように新しい名前のオブジェクトに逆シリアル化されたオブジェクトをマップしますか? –

答えて

5

これを行うには、カスタムContractResolverを使用できます。基本的には、別のJSONプロパティ名にマップする各クラスメンバーに[JsonProperty]というアトリビュートを配置するのと同じ考えですが、リゾルバを使用してプログラムで行います。デシリアライズする直前に、リゾルバに希望するマッピングの辞書を渡すことができます。あなたのマッピングを含むDictionary<Type, Dictionary<string, string>>を構築する最初の、リゾルバを使用するには

class DynamicMappingResolver : DefaultContractResolver 
{ 
    private Dictionary<Type, Dictionary<string, string>> memberNameToJsonNameMap; 

    public DynamicMappingResolver(Dictionary<Type, Dictionary<string, string>> memberNameToJsonNameMap) 
    { 
     this.memberNameToJsonNameMap = memberNameToJsonNameMap; 
    } 

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
    { 
     JsonProperty prop = base.CreateProperty(member, memberSerialization); 
     Dictionary<string, string> dict; 
     string jsonName; 
     if (memberNameToJsonNameMap.TryGetValue(member.DeclaringType, out dict) && 
      dict.TryGetValue(member.Name, out jsonName)) 
     { 
      prop.PropertyName = jsonName; 
     } 
     return prop; 
    } 
} 

:ここ

は、カスタムリゾルバのコードがどのように見えるかです。外側の辞書のキーは、プロパティをマップしたいクラスの型です。内部ディクショナリは、JSONプロパティ名へのクラスプロパティ名のマッピングです。名前がJSONとまだ一致していないプロパティのマッピングを提供するだけで済みます。

だから、例えば、あなたのJSONは、この(detailsオブジェクト内のプロパティの変更名前を気づく)...

{ 
    "values": { 
     "details": { 
      "foo": "94", 
      "bar": "47", 
      "baz": "32", 
      "quux": 1 
     }, 
     count: 4 
    } 
} 

のように見えた...そして、あなたがクラスにマッピングしたい場合

var map = new Dictionary<Type, Dictionary<string, string>> 
{ 
    { 
     typeof(Details), 
     new Dictionary<string, string> 
     { 
      {"property1", "foo"}, 
      {"property2", "bar"}, 
      {"property3", "baz"}, 
      {"property4", "quux"} 
     } 
    } 
}; 

最後のステップは、新しいリゾルバインスタンスとシリアライザの設定をセットアップしたばかりの構築それにマッピング辞書を与え、その後に設定を渡すことです:あなたの質問に、あなたはこのような辞書を作成しますJsonConvert.DeserializeObject()。ここで

var settings = new JsonSerializerSettings 
{ 
    ContractResolver = new DynamicMappingResolver(map) 
}; 

var root = JsonConvert.DeserializeObject<RootObject>(json, settings); 

はデモです:https://dotnetfiddle.net/ULkB0J

+0

まさに私が探していたものです。ありがとう!! –

0

JSON.netが探しているものをサポートしているとは思われません。フォーマットを知らない場合はJSONをJObjectに逆シリアル化する必要があります(たとえば、JSONが常にproperty1と表示されている場合は、それを表す汎用オブジェクトを使用できます)。

一般オブジェクトを取得したら、次にフィールドを翻訳する必要があります。変更できないものは直接行うことができますが、何か他にはReflectionを使う必要があります。

基本的には、タイプ(typeof(Details)またはobj.GetType())を取得し、更新するプロパティを検索します。最後に、セッターメソッドを見つけて、ジェネリックオブジェクトから元の値を渡して呼び出すことができるはずです。

1

はなぜ、ワンステップでこれを行いますか?標準オブジェクトに逆シリアル化してから、Automapperを使用して動的にマッピングするのはなぜですか?

のようなもの:

Mapper.Initialize(c => 
{ 
    c.ReplaceMemberName("property1 ", "differen_property_name1"); 
}); 
関連する問題