2014-12-16 42 views
13

Rozważmy Poniższy przykładowy programModyfikuj istniejący obiekt o nowych częściowych danych JSON z wykorzystaniem Json.NET

var calendar = new Calendar 
{ 
    Id = 42, 
    CoffeeProvider = "Espresso2000", 
    Meetings = new[] 
    { 
     new Meeting 
     { 
      Location = "Room1", 
      From = DateTimeOffset.Parse("2014-01-01T00:00:00Z"), 
      To = DateTimeOffset.Parse("2014-01-01T01:00:00Z") 
     }, 
     new Meeting 
     { 
      Location = "Room2", 
      From = DateTimeOffset.Parse("2014-01-01T02:00:00Z"), 
      To = DateTimeOffset.Parse("2014-01-01T03:00:00Z") 
     }, 
    } 
}; 

var patch = @"{ 
     'coffeeprovider': null, 
     'meetings': [ 
      { 
       'location': 'Room3', 
       'from': '2014-01-01T04:00:00Z', 
       'to': '2014-01-01T05:00:00Z' 
      } 
     ] 
    }"; 

var patchedCalendar = Patch(calendar, patch); 

Wynikiem metody Patch() powinna być równa calendar wyjątkiem zmieniony przez patch. To znaczy; Id byłby niezmieniony, CoffeeProvider byłby ustawiony na null, a Meetings zawierałby pojedynczy element znajdujący się w Room3.

  1. jaki sposób można stworzyć ogólny Patch() metodę, która będzie pracować dla dowolny obiekt (nie tylko przykładem Kalendarz obiekt) deserializable przez Json.NET?

  2. Jeśli (1) nie jest to wykonalne, jakie byłyby ograniczenia, które umożliwiłyby jego wykonanie i jak byłoby to możliwe?

+1

Może źle zrozumiałem pytanie. Czy chcesz zmodyfikować swój obiekt, sklonować go i zmodyfikować klon? – dbc

+0

Zmiana działa najlepiej w moim scenariuszu. Jeśli jednak istnieje wbudowana funkcja klonowania, nie miałbym nic przeciwko temu, żeby to zrobić. Jeśli nie ma wbudowanej funkcji, mógłbym po prostu głęboko sklonować obiekt (na przykład serializując + deserializując) przed jego łataniem. – Linus

+1

potrzebne jest głębokie klonowanie za pośrednictwem Json.Net. Zaktualizowana odpowiedź za pomocą prototypu. – dbc

Odpowiedz

15

Chcesz JsonSerializer.Populate() lub jego metoda statyczna JsonConvert.PopulateObject() wrapper:

zapełnia wartości JSON na obiekt docelowy.

Na przykład, tutaj jest aktualizowanie instancji klasy Calendar:

public static class TestPopulate 
{ 
    public static void Test() 
    { 
     var calendar = new Calendar 
     { 
      Id = 42, 
      CoffeeProvider = "Espresso2000", 
      Meetings = new[] 
      { 
       new Meeting 
       { 
        Location = "Room1", 
        From = DateTimeOffset.Parse("2014-01-01T00:00:00Z"), 
        To = DateTimeOffset.Parse("2014-01-01T01:00:00Z") 
       }, 
       new Meeting 
       { 
        Location = "Room2", 
        From = DateTimeOffset.Parse("2014-01-01T02:00:00Z"), 
        To = DateTimeOffset.Parse("2014-01-01T03:00:00Z") 
       }, 
      } 
     }; 

     var patch = @"{ 
    'coffeeprovider': null, 
    'meetings': [ 
     { 
      'location': 'Room3', 
      'from': '2014-01-01T04:00:00Z', 
      'to': '2014-01-01T05:00:00Z' 
     } 
    ] 
}"; 
     Patch(calendar, patch); 

     Debug.WriteLine(JsonConvert.SerializeObject(calendar, Formatting.Indented)); 
    } 

    public static void Patch<T>(T obj, string patch) 
    { 
     var serializer = new JsonSerializer(); 
     using (var reader = new StringReader(patch)) 
     { 
      serializer.Populate(reader, obj); 
     } 
    } 
} 

a wyjście debugowania produkowany jest:

{ 
    "id": 42, 
    "coffeeprovider": null, 
    "meetings": [ 
    { 
     "location": "Room3", 
     "from": "2014-01-01T04:00:00+00:00", 
     "to": "2014-01-01T05:00:00+00:00" 
    } 
    ] 
} 

Aktualizacja

Jeśli chcesz najpierw skopiować, możesz zrobić:

public static T CopyPatch<T>(T obj, string patch) 
    { 
     var serializer = new JsonSerializer(); 

     var json = JsonConvert.SerializeObject(obj); 
     var copy = JsonConvert.DeserializeObject<T>(json); 

     using (var reader = new StringReader(patch)) 
     { 
      serializer.Populate(reader, copy); 
     } 

     return copy; 
    }