fbpx
devstyle.pl - Blog dla każdego programisty
devstyle.pl - Blog dla każdego programisty
3 minut

Serializacja i deserializacja interfejsów


21.06.2011

Musiałem ostatnio serializować (no i oczywiście deserializować) kolekcje obiektów z hierarchii wyglądające na przykład tak:

  1:  public interface IExecutableAction
  2:  {
  3:      
  4:  }
  5:  
  6:  public class ReduceValue : IExecutableAction
  7:  {
  8:      public decimal ReduceBy;
  9:  
 10:      public ReduceValue()
 11:      {
 12:  
 13:      }
 14:  
 15:      public ReduceValue(decimal reduceBy)
 16:      {
 17:          ReduceBy = reduceBy;
 18:      }
 19:  }
 20:  
 21:  public class LockObject : IExecutableAction
 22:  {
 23:      public double Duration;
 24:      public string Reason;
 25:  
 26:      public TimeSpan GetDurationSpan()
 27:      {
 28:          return TimeSpan.FromMilliseconds(Duration);
 29:      }
 30:  
 31:      public LockObject()
 32:      {
 33:  
 34:      }
 35:  
 36:      public LockObject(TimeSpan duration, string reason)
 37:      {
 38:          Duration = duration.TotalMilliseconds;
 39:          Reason = reason;
 40:      }
 41:  }

Pierwszym kierunkiem był XML, jednak (zgodnie z oczekiwaniami zresztą) umożliwienie serializacji czegoś takiego do XMLa wiązałoby się z wieloma nieprzyjemnościami. A to nie można serializować interfejsów więc konieczne by było dodawanie jakiejś klasy abstrakcyjnej, a to trzeba stosować przebrzydłe atrybuty Xmlinclude żeby umożliwić deserializację… a dodatkowo korzystanie z serializatora xml jest niewygodne.

Co zrozumiałe – serializacja do JSON odpadała bo JSON nie zawiera informacji o źródłowym typie co, jak można się domyślić, znacząco utrudnia deserializację obiektu.

ALE! Po chwili moją uwagę przykuł konstruktor klasy JavaScriptSerializer przyjmujący parametr tajemniczego typu JavaScriptTypeResolver. Szczęśliwie okazało się, że wystarczy podać jego standardowo dostarczaną implementację (SimpleTypeResolver) i życie staje się prostsze! Wynikowy tekst zawiera wówczas, oprócz suchych danych, także informacje o typie serializowanej klasy. Takie coś śmiga aż miło:

  1:  [Test]
  2:  public void actions_can_be_serialized_and_deserialized()
  3:  {
  4:      var actions = new IExecutableAction[]
  5:                            {
  6:                                new ReduceValue(3),
  7:                                new LockObject(5.Minutes(), "reason")
  8:                            };
  9:  
 10:      var javaScriptSerializer = new JavaScriptSerializer(new SimpleTypeResolver());
 11:      string json = javaScriptSerializer.Serialize(actions);
 12:      var deserialized = javaScriptSerializer.Deserialize<IExecutableAction[]>(json);
 13:  
 14:      Assert.AreEqual(2, deserialized.Length);
 15:      Assert.AreEqual(3, ((ReduceValue)deserialized[0]).ReduceBy);
 16:      Assert.AreEqual(5.Minutes(), ((LockObject)deserialized[1]).GetDurationSpan());
 17:  }

Czyż nie cool? Jak to fajnie, że człowiek uczy się całe życie.

A żeby nie musieć za każdym razem pamiętać o tym "jak te akcje (de)serializować" banalna własna implementacja serializatora wydaje się sensownym krokiem dalej:

  1:  public class ExecutableActionsSerializer : JavaScriptSerializer
  2:  {
  3:      public ExecutableActionsSerializer() : base(new SimpleTypeResolver())
  4:      {
  5:      }
  6:  }
0 0 votes
Article Rating
5 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
marek
12 years ago

Dobre!

Dzięki,
Marek

jj
jj
12 years ago

Wklej przykładowego JSON’a jakiego to generuje. Zakładam że gdzieś w cwany sposób ukrywa typ?

procent
12 years ago

jj,
Po prostu każdy obiekt dostaje dodatkowe pole o nazwie "__type". Ale można to sobie zmienic, o tym w kolejnym odcinku:).

jj
jj
12 years ago

Maćjek…. nie kasz czekać!! wklei kawałek kodó!

procent
12 years ago

Ależ jaki niecierpliwy!
Teraz kodu obok nie mam, ale jak normalny obiekt Person wygląda tak:
{ Age: 13, Name: ‘name’ }
to po potraktowaniu tym mechanizmem:
{ __type:’Some.Namespace.Person, some.dll, version=…., key=…. ‘, Age: 13, Name: ‘name’ }

Kurs Gita

Zaawansowany frontend

Szkolenie z Testów

Szkolenie z baz danych

Książka

Zobacz również