2012-10-31 13 views
20

Używam BinaryFormatter do serializacji binarnej niektórych obiektów w języku C#. Jednak niektóre obiekty zawierają klasy, do których uzyskuję dostęp za pośrednictwem biblioteki DLL i nie mają kodu źródłowego, więc nie mogę oznaczyć ich atrybutem Serializable. Czy istnieje jakiś prosty sposób na serializowanie ich? Mam obejście, które obejmuje wzięcie klasy NoSource i utworzenie nowej klasy SerializableNoSource, dla której konstruktor pobiera obiekt NoSource i wyodrębnia z niej wszystkie potrzebne informacje, ale jest zhakowany. Czy są jakieś lepsze alternatywy?Czy jest możliwe wykonanie serializacji binarnej .NET, gdy nie masz kodu źródłowego klasy?

+7

Dla zapisu, enkapsulacja obiektu w innym obiekcie, który * nie * wie, jak szeregować siebie, jak również konwersja do/z enkapsulowanego obiektu nie jest w moim umyśle hacky, jest całkowicie odpowiednia. Teraz może być coś lepszego lub lepszego, ale nie uważam, że twoje obecne podejście jest zasadniczo wadliwe. – Servy

Odpowiedz

-2

Myślę, że czystszym sposobem byłoby implicment ISerializable Interface i zarządzanie serializacją i procesem odwrotnym. W MSDN możemy znaleźć:

serializacji nie może zostać dodany do klasy po jej skompilowany ....

+0

"Jednak niektóre obiekty zawierają klasy, do których uzyskuję dostęp przez bibliotekę DLL i nie mają kodu źródłowego dla" –

+0

Możesz myśleć, że tworzę własną klasę, która może mieć takie same właściwości jak obiekt, w którym nie masz źródła Nie? Lub rozszerza to? –

+0

Rozszerzenie nie działa, kopiowanie właściwości ... to jest to samo, co teraz ma teraz –

1

Możesz być w stanie wykorzystać Mono.Cecil dodać [SerializableAttribute] do klas , ale nie zrobiłbym tego, jeśli istnieje inny sposób osiągnięcia pożądanego rezultatu.

0

Zgadzam się z @Servy, jeśli autor klasy nie spodziewał się, że będzie serializowany, nie należy próbować przekształcać go bezpośrednio do postaci szeregowej. Więc robisz to, co należy, z architektonicznego punktu widzenia. Aby zmniejszyć obecne podejście, "hacky", rozważ implementację ISerializable dla klas, które zawierają odniesienia do obiektów niezdolnych do serializacji.

0

Utwórz nową klasę, dziedzicz istniejącą klasę, która nie jest oznaczona atrybutem serializacji i implementuj interfejs ISerializable.

Jeśli zajęcia są zapieczętowane, możesz użyć Json.NET, a następnie przekonwertować je na wersję binarną i na odwrót (bardzo się przydaje, użyj go, jeśli nic innego nie pomoże :)).

20

Można utworzyć surogat serializacyjny .

Wyobraźmy sobie, że mamy klasy określone w wymienionej zespołu, że nie mamy kontroli nad, który wygląda tak:

public class Person 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 
    public DriversLicense License; 
} 


// An instance of this type will be part of the object graph and will need to be 
// serialized also. 
public class DriversLicense 
{ 
    public string Number { get; set; } 
} 

W celu serializacji ten cel trzeba będzie zdefiniować surogat serializacji dla każdego typu na wykresie obiektu.

Aby utworzyć surogat serializacji wystarczy stworzyć typ, który implementuje interfejs ISerializationSurrogate:

public class PersonSurrogate : ISerializationSurrogate 
{ 
    /// <summary> 
    /// Manually add objects to the <see cref="SerializationInfo"/> store. 
    /// </summary> 
    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) 
    { 
     Person person = (Person) obj; 
     info.AddValue("Name", person.Name); 
     info.AddValue("Age", person.Age); 
     info.AddValue("License", person.License); 
    } 

    /// <summary> 
    /// Retrieves objects from the <see cref="SerializationInfo"/> store. 
    /// </summary> 
    /// <returns></returns> 
    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) 
    { 
     Person person = (Person)obj; 
     person.Name = info.GetString("Name"); 
     person.Age = info.GetInt32("Age"); 
     person.License = (DriversLicense) info.GetValue("License", typeof(DriversLicense)); 
     return person; 
    } 
} 

public class DriversLicenseSurrogate : ISerializationSurrogate 
{ 
    /// <summary> 
    /// Manually add objects to the <see cref="SerializationInfo"/> store. 
    /// </summary> 
    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) 
    { 
     DriversLicense license = (DriversLicense)obj; 
     info.AddValue("Number", license.Number); 
    } 

    /// <summary> 
    /// Retrieves objects from the <see cref="SerializationInfo"/> store. 
    /// </summary> 
    /// <returns></returns> 
    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) 
    { 
     DriversLicense license = (DriversLicense)obj; 
     license.Number = info.GetString("Number"); 
     return license; 
    } 
} 

Następnie trzeba pozwolić IFormatter wiedzieć o surogatów poprzez definiowanie i inicjowanie SurrogateSelector i przypisanie go do twój IFormatter.

private static void SerializePerson(Person person) 
{ 
    if (person == null) 
     throw new ArgumentNullException("person"); 

    using (var memoryStream = new MemoryStream()) 
    { 
     //Configure our surrogate selectors. 
     var surrogateSelector = new SurrogateSelector(); 
     surrogateSelector.AddSurrogate(typeof (Person), new StreamingContext(StreamingContextStates.All), 
             new PersonSurrogate()); 
     surrogateSelector.AddSurrogate(typeof (DriversLicense), new StreamingContext(StreamingContextStates.All), 
             new DriversLicenseSurrogate()); 

     //Serialize the object 
     IFormatter formatter = new BinaryFormatter(); 
     formatter.SurrogateSelector = surrogateSelector; 
     formatter.Serialize(memoryStream, person); 

     //Return to the beginning of the stream 
     memoryStream.Seek(0, SeekOrigin.Begin); 

     //Deserialize the object 
     Person deserializedPerson = (Person) formatter.Deserialize(memoryStream); 
    } 
} 

Korzystanie z surogat serializacji nie jest wcale proste, a może rzeczywiście stać się bardzo gadatliwy, gdy typ próbujesz serializacji ma prywatne & chronionych obszarów, które muszą być w odcinkach.

Ale jak już ręcznie serializujesz potrzebne wartości, nie sądzę, że to jest problem.Używanie surogatu jest bardziej unifomicznym sposobem radzenia sobie z takim scenariuszem i powinno sprawić, że poczujesz się bardziej komfortowo.

+0

To wygląda na odpowiedź podręcznika, aby naprawdę serializować unowned klasy, która nie jest oznaczona '[Serializable]' –

+0

Jeśli chcesz więcej informacji możesz przeczytać rozdział 23 [CLR przez C#] (http://www.amazon.co.uk/CLR-via-C-Jeffrey-Richter/dp/0735627045) - Serializacja Runtime. –

+0

Znaleźliśmy również odpowiedni artykuł na temat MSDN: http://msdn.microsoft.com/en-us/magazine/cc188950.aspx –

Powiązane problemy