2013-10-17 8 views

答えて

21
public T GetFirstInstance<T>(string propertyName, string json) 
{ 
    using (var stringReader = new StringReader(json)) 
    using (var jsonReader = new JsonTextReader(stringReader)) 
    { 
     while (jsonReader.Read()) 
     { 
      if (jsonReader.TokenType == JsonToken.PropertyName 
       && (string)jsonReader.Value == propertyName) 
      { 
       jsonReader.Read(); 

       var serializer = new JsonSerializer(); 
       return serializer.Deserialize<T>(jsonReader); 
      } 
     } 
     return default(T); 
    } 
} 

public class MyType 
{ 
    public string Text { get; set; } 
} 

public void Test() 
{ 
    string json = "{ \"PropOne\": { \"Text\": \"Data\" }, \"PropTwo\": \"Data2\" }"; 

    MyType myType = GetFirstInstance<MyType>("PropOne", json); 

    Debug.WriteLine(myType.Text); // "Data" 
} 

このアプローチでは、オブジェクト全体をデシリアライズする必要がありません。しかし、これは、jsonがの場合には、大幅にであり、デシリアライズするプロパティが比較的早い場合にのみ、パフォーマンスが向上することに注意してください。それ以外の場合は、jcwrequests answerショーのように、すべてをデシリアライズして必要な部分を抜き出してください。

+0

再利用性を向上させるために若干更新されました。 –

+1

このメソッドは、ツリーのルートだけでなく、どのレベルでも最初のプロパティ "PropOne"をキャッチします。 レベルを追跡し、ルートレベルで正しいプロパティ名のみを受け入れることで修正できます。 – hultqvist

+0

これは、デコードしているJSON文字列が何であるか不明な場合や、それを理解するためにプロパティを読み取る必要がある場合にも便利です。 – starbeamrainbowlabs

1

JsonIgnoreを使用すると、Json.Netによってプロパティが完全に無視され、シリアル化とデシリアライズの両方が行われます。

また、linkにチェックを入れてください。

+0

私はむしろ、私は 'PropOne'と' PropTwo'を表す2つの別々のクラスを持っている、 'PropOne'と' PropTwo'の両方が含まれている複合オブジェクトを持っていません。 – Omar

+0

オブジェクトをシリアル化していますか? – NomadTraveler

+0

それが私がJSONを作成しているということを意味するならば、私はJSONを第三者に送ります。 – Omar

3
var json = "{ "PropOne": { "Text": "Data" } "PropTwo": "Data2" }"; 

JObject o = JObject.Parse(json); 
var val = o.PropTwo; 

JSON Linqプロバイダを使用すると、オブジェクトを既知の型に逆シリアル化する必要はありません。

27

JSONはそれほど大きくないので、私はMatt Johnsonの提案を受け取り、すべてを逆シリアル化します。

var jObject = JObject.Parse(json); 
var jToken = jObject.GetValue("PropTwo"); 
PropTwoClass value = jToken.ToObject(typeof(PropTwoClass)); 
4

Omar's answerに簡単な解決策は、ラッパーを持っているだろう。答えをjcwrequestsのおかげで、私はこの方法を使用することができました。

class Wrapper 
{ 
    public PropOneClass PropOne; 
} 

JsonConvert.Deserialize<Wrapper>(json).PropOne 

私のテストでは、約30%速くなっています。

1

Matt's answerこれはバグがありますが、はるかに速い解決方法です。 これを修正する試みです。 このメソッドは、ルートレベルで一致するプロパティのみを返します。 開始トークンと終了トークンのカウントにはまだまだ単純なアプローチがありますが、有効なJSONの場合はおそらく動作します。

Matt、これをあなたの答えに自由にコピーしてください。

public T GetFirstInstance<T>(string propertyName, string json) 
{ 
    using (var stringReader = new StringReader(json)) 
    using (var jsonReader = new JsonTextReader(stringReader)) 
    { 
     int level = 0; 

     while (jsonReader.Read()) 
     { 
      switch (jsonReader.TokenType) 
      { 
       case JsonToken.PropertyName: 
        if (level != 1) 
         break; 
        if ((string)jsonReader.Value == propertyName) 
        { 
         jsonReader.Read(); 

         return (T)jsonReader.Value; 
        } 
        break; 

       case JsonToken.StartArray: 
       case JsonToken.StartConstructor: 
       case JsonToken.StartObject: 
        level++; 
        break; 

       case JsonToken.EndArray: 
       case JsonToken.EndConstructor: 
       case JsonToken.EndObject: 
        level--; 
        break; 
      } 

     } 
     return default(T); 
    } 
} 
関連する問題