2016-06-21 15 views
0

Unten ist ein vereinfachtes Beispiel für das, was ich erreichen möchte.DataContractJsonSerializer; ISerializable GetObjectData mit .NET aufgerufen aber nicht mit Mono

Ich habe eine Klasse DoNotSerializeMe, die Teil einer externen Bibliothek ist und nicht serialisiert werden kann.

Ich habe auch eine Klasse SerializeMe, die ein Mitglied des Typs DoNotSerializeMe hat. Ich kann diese Klasse dazu bringen, ISerializable zu implementieren und das Problem zu umgehen, dass DoNotSerializeMe nicht serialisierbar ist, indem man Daten zieht und den Konstruktor aufruft.

using System.Runtime.Serialization; 
using System.Security.Permissions; 

namespace CustomJsonSerialization 
{ 
    [System.Serializable] 
    public class SerializeMe : ISerializable 
    { 
     public DoNotSerializeMe SerializeMeThroughISerializable; 

     public SerializeMe(string mystring) 
     { 
      SerializeMeThroughISerializable = new DoNotSerializeMe(mystring); 
     } 

     protected SerializeMe(SerializationInfo info, StreamingContext context) 
     { 
      System.Console.WriteLine(" In SerializeMe constructor (ISerializable)"); 
      SerializeMeThroughISerializable = new DoNotSerializeMe(info.GetString("SerializeMeThroughISerializable")); 
     } 

     [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] 
     public virtual void GetObjectData(SerializationInfo info, StreamingContext context) 
     { 
      System.Console.WriteLine(" In SerializeMe.GetObjectData()"); 
      info.AddValue("SerializeMeThroughISerializable", 
        "(deserialized through getObjectData " + 
        SerializeMeThroughISerializable.WhyAmIHere + ")"); 
     } 
    } 
} 

Im Folgenden finden Sie ein kurzes Programm, das das Objekt serialisiert und deserialisiert:

using System; 
using System.IO; 
using System.Runtime.Serialization.Json; 
using System.Text; 

namespace CustomJsonSerialization 
{ 
    public class Program 
    { 
     public static void Main(string[] args) 
     { 
      SerializeMe serializeme = new SerializeMe("initial"); 

      Console.WriteLine("I created it: {0}", serializeme.SerializeMeThroughISerializable.WhyAmIHere); 
      Console.WriteLine(); 

      MemoryStream memstream = new MemoryStream(); 
      DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(SerializeMe)); 
      serializer.WriteObject(memstream, serializeme); 

      Console.WriteLine("I serialized it: {0}", serializeme.SerializeMeThroughISerializable.WhyAmIHere); 
      Console.WriteLine(); 

      Console.WriteLine("Json:"); 
      Console.WriteLine(Encoding.ASCII.GetString(memstream.ToArray())); 
      Console.WriteLine(); 

      memstream.Seek(0, SeekOrigin.Begin); 
      SerializeMe anotherSerializeMe = (SerializeMe)serializer.ReadObject(memstream); 
      Console.WriteLine("I deserialized it: {0}", anotherSerializeMe.SerializeMeThroughISerializable.WhyAmIHere); 

     } 
    } 
} 

Wenn durch .NET (4.5) ausgeführt wird, erhalte ich folgendes:

In DoNotSerializeMe constructor. 
I created it: (constructed with initial) 

    In SerializeMe.GetObjectData() 
I serialized it: (constructed with initial) 

Json: 
{"SerializeMeThroughISerializable":"(deserialized through getObjectData (constructed with initial))"} 

    In SerializeMe constructor (ISerializable) 
    In DoNotSerializeMe constructor. 
I deserialized it: (constructed with (deserialized through getObjectData (constructed with initial))) 

Der Serializer genannt die ISerializable-Konstruktion und die GetObjectData beim Serialisieren/Deserialisieren (wie erwartet). Ich serialisiert oder deserialisiert das DoNotSerializeMe-Objekt nicht direkt.

Allerdings, wenn Sie die gleiche Build über Mono (versuchte 3.10.0 und 4.0.2) ausführen, bekomme ich Folgendes: In DoNotSerializeMe Konstruktor. ich es erstellt: (mit anfänglichem gebaut)

I serialized it: (constructed with initial) 

Json: 
{"SerializeMeThroughISerializable":{"WhyAmIHere":"(constructed with initial)"}} 

I deserialized it: (constructed with initial) 

Offensichtlich wenn DoNotSerializeMe wirklich nicht serialisierbar waren, würde dies zu einem Fehler führen.

Gibt es eine elegante Möglichkeit, dies ohne Json.NET zu umgehen? Ich bin mir nicht sicher, warum mono verhält sich nicht so wie .NET.

+1

, welche Version von Mono verwenden Sie? – knocte

+0

@knocte, habe ich 3.10.0 und 4.0.2 versucht. – Jaws

+0

Ich empfehle Ihnen, mit einer Version zu testen, die so modern ist wie die von Ubuntu 16.04 beinhaltet, zumindest (was ich denke, es ist 4.2.3) – knocte

Antwort

0

Ich werde einen alternativen Ansatz vorschlagen: Verwenden Sie einen Surrogat-Datenübertragungs-Typ, um Ihre DoNotSerializeMe-Klasse zu serialisieren. Ein Weg, dies zu tun ist mit Data Contract Surrogates. Aber werden Datenvertragsurrogate auf Mono unterstützt? Die current version of the source code zeigt, dass sie sind, aber this version zeigt es als [MonoTODO], so kann ich nicht garantieren, dass Ihre Version von Mono eine funktionierende Implementierung für DataContractJsonSerializer.DataContractSurrogate hat.

Eine manuelle Ersatzeigenschaft wird jedoch immer funktionieren. Zum Beispiel kann die folgende SerializeMe Typ serialisiert und serialisiert werden, obwohl seine DoNotSerializeMe Mitglied nicht direkt serialisiert werden kann:

public class DoNotSerializeMe 
{ 
    public readonly string WhyAmIHere; 
    readonly bool ProperlyConstructed; // data contract serializer does not call the constructor 

    public DoNotSerializeMe(string mystring) 
    { 
     Console.WriteLine(string.Format(" In DoNotSerializeMe constructor, mystring = \"{0}\"", mystring)); 
     WhyAmIHere = mystring; 
     ProperlyConstructed = true; 
    } 

    public void Validate() 
    { 
     if (!ProperlyConstructed) 
      throw new InvalidOperationException("!ProperlyConstructed"); 
    } 
} 

public class SerializeMe 
{ 
    [IgnoreDataMember] 
    public DoNotSerializeMe CannotBeSerializedDirectly; 

    public DoNotSerializeMeSurrogate DoNotSerializeMeSurrogate 
    { 
     get 
     { 
      if (CannotBeSerializedDirectly == null) 
       return null; 
      return new DoNotSerializeMeSurrogate { WhyAmIHereSurrogate = CannotBeSerializedDirectly.WhyAmIHere }; 
     } 
     set 
     { 
      if (value == null) 
       CannotBeSerializedDirectly = null; 
      else 
       CannotBeSerializedDirectly = new DoNotSerializeMe(value.WhyAmIHereSurrogate); 
     } 
    } 

    public string SomeOtherField { get; set; } 
} 

public class DoNotSerializeMeSurrogate 
{ 
    public string WhyAmIHereSurrogate { get; set; } 
} 

Mit diesem Ansatz sieht einfacher als die Umsetzung ISerializable da alle Mitglieder außer CannotBeSerializedDirectly weiterhin automatisch serialisiert werden. Beachten Sie die Verwendung von [IgnoreDataMember]. Es verhindert, dass das Element CannotBeSerializedDirectly in den impliziten Datenvertrag für die Klasse eingeschlossen wird.

Wenn Sie Ihre Ersatz lieber privat sein, oder müssen die Surrogat Mitgliedernamen zu steuern, müssen Sie das enthalten, geben Sie eine explizite Daten Vertrag geben:

[DataContract] 
public class SerializeMe 
{ 
    [IgnoreDataMember] 
    public DoNotSerializeMe CannotBeSerializedDirectly; 

    [DataMember] 
    DoNotSerializeMeSurrogate DoNotSerializeMeSurrogate 
    { 
     get 
     { 
      if (CannotBeSerializedDirectly == null) 
       return null; 
      return new DoNotSerializeMeSurrogate { WhyAmIHereSurrogate = CannotBeSerializedDirectly.WhyAmIHere }; 
     } 
     set 
     { 
      if (value == null) 
       CannotBeSerializedDirectly = null; 
      else 
       CannotBeSerializedDirectly = new DoNotSerializeMe(value.WhyAmIHereSurrogate); 
     } 
    } 

    [DataMember] 
    public string SomeOtherField { get; set; } 
} 

[DataContract] 
class DoNotSerializeMeSurrogate 
{ 
    [DataMember] 
    public string WhyAmIHereSurrogate { get; set; } 
} 
+1

das ist eine elegante Lösung, und Sie haben Recht, das sollte funktionieren. Ich habe private Felder verwendet und [OnSerializing] [OnDeserialized], aber ich mag es nicht. Also werde ich definitiv Ihre Lösung ausprobieren und Sie wissen lassen. Vielen Dank! – Jaws