2012-07-23 5 views
2

J'essaie de sérialiser un message immuable qui a une classe de base immuable. Cependant, je suis incapable de convaincre protobuf-serializer de le désérialiser en un type dérivé. En bref ce test me donne une exception coulée non valide (de la base au dérivé):Protobuf-net et l'héritage des messages immuables

[TestFixture] 
public class InheritanceTest 
{ 
    public class Base 
    { 
     public int IntField { get; private set; } 

     public Base(int intField) 
     { 
      IntField = intField; 
     } 
    } 

    public class Derived : Base 
    { 
     public string StringField { get; private set; } 

     public Derived(int intField, string stringField) : base(intField) 
     { 
      StringField = stringField; 
     } 
    } 

    [Test] 
    public void TestInheritance() 
    { 
     var serializer = TypeModel.Create(); 
     serializer.Add(typeof (Base), true) 
      .Add(1, "IntField") 
      .AddSubType(2, typeof (Derived)) 
      .UseConstructor = false; 

     serializer.Add(typeof (Derived), true) 
      .Add(1, "StringField") 
      .UseConstructor = false; 

     serializer.CompileInPlace(); 

     using (var stream = new MemoryStream()) 
     { 
      var message = new Derived(1, "Some text that is not important"); 

      serializer.Serialize(stream, message); 
      stream.Position = 0; 

      var retrieved = (Derived) serializer.Deserialize(stream, null, typeof (Derived)); 

      Assert.AreEqual(message.IntField, retrieved.IntField); 
      Assert.AreEqual(message.StringField, retrieved.StringField); 
     } 
    } 

} 

Cette exception disparaît si je convertir la base et dérivés à des types mutables. Est-ce que je fais quelque chose de mal ou est-ce une limitation de protobuf-net?

Répondre

0

Cela semble être un effet secondaire du tuple-détection, l'amenant à avoir une branche de code spécifique. Le bon nes est, vous devriez être en mesure de corriger cela à partir de votre code d'origine, simplement en changeant true à false. Ce paramètre indique s'il faut ou non appliquer des comportements standard. Vous n'en avez pas besoin puisque vous définissez vous-même le modèle.

 var serializer = TypeModel.Create(); 
     serializer.Add(typeof (Base), false) 
      .Add(1, "IntField") 
      .AddSubType(2, typeof (Derived)) 
      .UseConstructor = false; 

     serializer.Add(typeof (Derived), false) 
      .Add(1, "StringField") 
      .UseConstructor = false; 

Note Je n'ai pas vérifié ceci - je vérifierai plus tard cependant.

+0

Salut, oui - changer cela à faux a aidé. La raison pour laquelle ils étaient vrais était parce que j'utilise en fait ma propre interface fluide qui définit les membres en utilisant des expressions au lieu de chaînes et je voulais conserver un comportement standard au cas où je serais obligé d'utiliser plus tard des attributs. Accepter cette réponse à la place car il est susceptible de causer moins de problèmes avec l'héritage (puisque le sous-type est connu pour le sérialiseur). –

+0

@VytautasMackonis Fondamentalement: il frappait cette logique: http://marcgravell.blogspot.co.uk/2011/08/automatic-serialization-whats-in-tuple.html - Je vais vérifier plus tard si cela peut être évité dans le futur –

1
[TestFixture] 
public class InheritanceTest 
{ 
    public class Base 
    { 
     public int IntField { get; private set; } 

     public Base(int intField) 
     { 
      IntField = intField; 
     } 
    } 

    public class Derived : Base 
    { 
     public string StringField { get; private set; } 

     public Derived(int intField, string stringField) : base(intField) 
     { 
      StringField = stringField; 
     } 
    } 

    [Test] 
    public void TestInheritance() 
    { 
     var serializer = TypeModel.Create(); 
     serializer.Add(typeof (Base), true) 
      .Add(1, "IntField") 
      .UseConstructor = false; 

     serializer.Add(typeof (Derived), true) 
      .Add(1, "StringField") 
      .UseConstructor = false; 

     serializer.CompileInPlace(); 

     using (var stream = new MemoryStream()) 
     { 
      var message = new Derived(1, "Some text that is not important"); 

      serializer.Serialize(stream, message); 
      stream.Position = 0; 

      var retrieved = (Derived) serializer.Deserialize(stream, null, typeof (Derived)); 

      Assert.AreEqual(message.IntField, retrieved.IntField); 
      Assert.AreEqual(message.StringField, retrieved.StringField); 
     } 
    } 

} 

ou

[TestFixture] 
    public class InheritanceTest 
    { 
     [DataContract] 
     public class Base 
     { 
      [DataMember(Order = 1)] 
      public int IntField { get; private set; } 

      public Base(int intField) 
      { 
       IntField = intField; 
      } 
      protected Base(){} 
     } 

     [DataContract] 
     public class Derived : Base 
     { 
      [DataMember(Order = 3)] 
      public string StringField { get; private set; } 

      public Derived(int intField, string stringField) : base(intField) 
      { 
       StringField = stringField; 
      } 
      private Derived(){} 
     } 

     [Test] 
     public void TestInheritance() 
     { 
      RuntimeTypeModel.Default.Add(typeof(Base), true).AddSubType(2, typeof(Derived)); 

      using (var stream = new MemoryStream()) 
       { 
        var message = new Derived(1, "Some text that is not important"); 

        Serializer.Serialize(stream, message); 
        stream.Position = 0; 

        var retrieved = Serializer.Deserialize<Derived>(stream);    

        Assert.AreEqual(message.IntField, retrieved.IntField); 
        Assert.AreEqual(message.StringField, retrieved.StringField); 
      } 
     } 

    } 
+0

N'existe-t-il aucun moyen de configurer le même comportement sans placer les classes sérialisées avec des attributs? Ou des constructeurs privés/protégés? –

+0

@VytautasMackonis vous devez définir des numéros de champ pour chaque membre que vous souhaitez sérialiser. Le protocole de protobuf sous-jacent nécessite un numéro de champ unique pour chaque champ dans un seul message. Voir ici: https://developers.google.com/protocol-buffers/docs/proto pour plus d'informations :) – Franchesca

+0

mis à jour, vous voulez version supérieure –