2013-10-17 7 views

Odpowiedz

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" 
} 

Takie podejście pozwala uniknąć deserializacji całego obiektu. Należy jednak pamiętać, że poprawi to wydajność tylko wtedy, gdy json jest duży, a właściwość deserializacji jest relatywnie wcześnie w danych. W przeciwnym razie powinieneś po prostu odserializować całość i wyciągnąć części, które chcesz, np. Odpowiedzi na pytania dotyczące jcwwtów.

+0

Zaktualizowany nieznacznie dla lepszej przydatności do ponownego użycia. –

+1

Ta metoda jest zepsuta tym, że przechwyci pierwszą właściwość "PropOne" w dowolnym miejscu na dowolnym poziomie, a nie tylko w katalogu głównym drzewa. Można to naprawić, śledząc poziom i akceptując tylko poprawną nazwę właściwości na poziomie katalogu głównego. – hultqvist

+0

Pamiętaj, że może to być przydatne, jeśli nie masz pewności, jaki ciąg znaków JSON dekodujesz, i musisz przeczytać właściwość, aby to zrozumieć. – starbeamrainbowlabs

1

Użyj JsonIgnore - spowoduje to całkowite zignorowanie właściwości przez Json.Net, zarówno w przypadku serializacji, jak i deserializacji.

Sprawdź również to link.

+0

nie mam kompozytowego obiekt, który zawiera zarówno '' PropTwo' PropOne' i raczej mam dwie odrębne klasy, które reprezentują 'PropOne' i' PropTwo'. – Omar

+0

Czy serializujesz również obiekty? – NomadTraveler

+0

Jeśli przez to masz na myśli to ja tworzę JSON, to nie, JSON, który dostaję jest wysyłany przez 3rd party. – Omar

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

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

Korzystając z dostawcy JSON Linq, nie trzeba przekształcać obiektu w postać znaną.

27

JSON nie jest zbyt duży, więc przyjmuję sugestię Matta Johnsona i deserializację całości. Dzięki jcwrequests odpowiedzieć, byłem w stanie skorzystać z tej metody:

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

Prostszym rozwiązaniem Omar's answer byłoby mieć otoki.

class Wrapper 
{ 
    public PropOneClass PropOne; 
} 

JsonConvert.Deserialize<Wrapper>(json).PropOne 

Moje testy wykazały, że jest o 30% szybszy.

1

Matt's answer jest zdecydowanie najszybszym rozwiązaniem, chociaż ma błąd. To jest moja próba naprawienia tego. Ta metoda zwróci tylko pasującą właściwość na poziomie katalogu głównego. Istnieje wciąż naiwne podejście do liczenia żetonów początkowych i końcowych, chociaż dla poprawnego JSON prawdopodobnie będzie działać.

Matt, możesz skopiować to do swojej odpowiedzi.

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); 
    } 
}