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

Nie przegap kolejnych postów!

Dołącz do ponad 9000 programistów w devstyle newsletter!

Tym samym wyrażasz zgodę na otrzymanie informacji marketingowych z devstyle.pl (doh...). Powered by ConvertKit
Notify of
marek

Dobre!

Dzięki,
Marek

jj
jj

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

procent

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

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

procent

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

Szkolenie z testów

Facebook

Książka

Zobacz również