2011-07-27 8 views
5

estoy usando la versión 2 de protobuf-net, y actualmente estoy que consigue el error "No se puede determinar miembro de: Un"¿Está permitido el <T> en un modelo ProtoBuf-net en tiempo de ejecución?

¿Es posible crear un modelo de tiempo de ejecución para Protobuf-net cuando usamos ClassOfType < T>? Si es así, ¿alguien puede detectar lo que me falta en el código siguiente?

por cierto: esta solicitud se modela fuera de Deserialize unknown type with protobuf-net que pude conseguir una versión de esta yendo muy bien ... pero que están utilizando una clase base abstracta, no una clase genérica de T.

ESTE ES UN TRABAJO EJEMPLO (las cosas que no funcionaban se eliminan).

using System; 
using System.IO; 
using NUnit.Framework; 
using ProtoBuf; 
using ProtoBuf.Meta; 

namespace ProtoBufTestA2 
{ 
    [TestFixture] 
    public class Tester 
    { 
     [Test] 
     public void TestMsgBaseCreateModel() 
     { 
      var BM_SD = new Container<SomeDerived>(); 

      using (var o = BM_SD) { 
       o.prop1 = 42; 
       o.payload = new SomeDerived(); 
       using (var d = o.payload) { 
        d.SomeBaseProp = -42; 
        d.SomeDerivedProp = 62; 
       } 
      } 

      var BM_SB = new Container<SomeBase>(); 
      using (var o = BM_SB) { 
       o.prop1 = 42; 
       o.payload = new SomeBase(); 
       using (var d = o.payload) { 
        d.SomeBaseProp = 84; 
       } 
      } 
      var model = TypeModel.Create(); 

      model.Add(typeof(Container<SomeDerived>), true); // BM_SD 
      model.Add(typeof(Container<SomeBase>), true); // BM_SB 
      model.Add(typeof(SomeBase), true); // SB 
      model.Add(typeof(SomeDerived), true); // SD 
      model[typeof(SomeBase)].AddSubType(50, typeof(SomeDerived)); // SD 

      var ms = new MemoryStream(); 

      model.SerializeWithLengthPrefix(ms, BM_SD, BM_SD.GetType(), ProtoBuf.PrefixStyle.Base128, 0); 

      model.SerializeWithLengthPrefix(ms, BM_SB, BM_SB.GetType(), ProtoBuf.PrefixStyle.Base128, 0); 
      ms.Position = 0; 
      var o1 = (Container<SomeDerived>)model.DeserializeWithLengthPrefix(
       ms 
       , null 
       , typeof(Container<SomeDerived>), PrefixStyle.Base128, 0); 
      var o2 = (Container<SomeBase>)model.DeserializeWithLengthPrefix(
       ms 
       , null 
       , typeof(Container<SomeBase>), PrefixStyle.Base128, 0); 
     } 
    } 

    [ProtoContract] 
    public class Container<T> : IDisposable 
    { 
     [ProtoMember(1)] 
     public int prop1 { get; set; } 

     [ProtoMember(2)] 
     public T payload { get; set; } 

     public void Dispose() { } 
    } 

    [ProtoContract] 
    public class AnotherDerived : SomeDerived, IDisposable 
    { 
     [ProtoMember(1)] 
     public int AnotherDerivedProp { get; set; } 
     public override void Dispose() { } 
    } 

    [ProtoContract] 
    public class SomeDerived : SomeBase, IDisposable 
    { 
     [ProtoMember(1)] 
     public int SomeDerivedProp { get; set; } 

     public override void Dispose() { } 
    } 

    [ProtoContract] 
    public class SomeBase : IDisposable 
    { 
     [ProtoMember(1)] 
     public int SomeBaseProp { get; set; } 

     public virtual void Dispose() { } 
    } 

    [ProtoContract] 
    public class NotInvolved : IDisposable 
    { 
     [ProtoMember(1)] 
     public int NotInvolvedProp { get; set; } 
     public void Dispose() { } 
    } 

    [ProtoContract] 
    public class AlsoNotInvolved : IDisposable 
    { 
     [ProtoMember(1)] 
     public int AlsoNotInvolvedProp { get; set; } 
     public void Dispose() { } 
    } 
} 

Solicitud

Ésta es menor, pero sería bueno si

(Container<SomeDerived>)model.DeserializeWithLengthPrefix(...) 

también podrían implementarse como esto

model.DeserializeWithLengthPrefix<Container<SomeDerived>>(...): 

por cierto: estoy comenzando a profundizar en la implementación de protobuf-net, y estoy empezando a notar algunos en métodos de investigación como este. Algo para volver a tarde supongo:

public MetaType Add(int fieldNumber, string memberName, Type itemType, Type defaultType); 

Discusión:

cuando vi la forma en que podría deserializar a un tipo de base abstracta en el enlace anterior, pensé, sí, eso es más cerca de que estaba pensando Podríamos deserializar al contenedor genérico abierto <> primero, y luego emitirlo más específicamente si lo necesitamos en diferentes ensamblajes. Quizás me estoy confundiendo un poco aquí.

Se podría pensar en términos de Tupple < TBase, TPayload>. O una variación como Tupple < TBase, Lazy < TPayload >> maybe. No es tan diferente a la lista < T>. Hay algunos TreeTypeThings < T> que tengo también, pero no necesito serializarlos/deserializarlos (todavía).

Tenía una secuencia no genérica funcionando, por lo que no es un stopper. Mi primera implementación podría ser más eficiente. Creo que puedo hacerlo mejor con las funciones existentes de protobuf-net.

Me gusta la manera más limpia de trabajar con estas ideas. Aunque puedo llegar al mismo destino manualmente, los genéricos hacen que otras cosas sean posibles.

re: aclaración

todo puede ser definido de antemano por la persona que llama. (Por cierto: ahora me tienes pensando en el escenario de tiempo de ejecución, pero no, no lo necesito).

+0

Re "No se puede miembro de determinar : A "- eso es simplemente porque * no hay ningún miembro llamado' A' *, por cierto. Del mismo modo 'B',' C', 'D' o' E'. –

+0

@Marc Gravell Voy a ver eso. Yo * pensé * que .Add (1, "A") también creó la etiqueta. No puede llegar tan lejos. Tiene sentido. Oops. – sgtz

+0

@Marc Gravell: Todo funcionó bien al final + cambié el código de ejemplo anterior para reflejar esto. Gracias de nuevo. Dejemos los genéricos abiertos como algo para mirar en otro momento. – sgtz

Respuesta

4

Así que piensa la pregunta se reduce a "¿Puedo usar un tipo genérico abierto como plantilla para un modelo protobuf", en cuyo caso la respuesta es "tal vez".Por el momento, vería BasicMsg<Foo> y BasicMsg<Bar> como tipos diferentes, y utilizaría el modelo de tipo de atributo, ya que no los reconocerá como definidos por [typeof(BasicMsg<>)]. Si ellos tienen atributos, probablemente funcione, pero no creo que esa fuera su intención, ¿no?

Este es un escenario interesante, y estoy abierto a la discusión al respecto. Sin embargo, una preocupación particular que tengo aquí es que la naturaleza de los genéricos en .NET significa que esto requeriría la participación en tiempo de ejecución, es decir, RuntimeTypeModel. No creo que pueda hacerlo funcionar en precompiladoTypeModel sin usar MakeGenericMethod que realmente quiero evitar tanto por razones de plataforma como de rendimiento. Pero como característica de tiempo de ejecución de full.NET, parece interesante.

(aclaración de lo anterior, si la persona que llama podría definir todos los T para BasicMsg<T> antes de tiempo, se convierte en un poco más factible; entonces lo que realmente se reduce a una metáfora plantilla modelo)

+0

gracias por echar un vistazo. Muy amable. Comentarios anteriores en lugar de tratar de encajarlos en un tweet x 3. – sgtz

+0

por cierto: comentarios ahora allí. Gracias. – sgtz

+0

¿es posible serializar un objeto con un tipo primitivo? He probado bastantes combinaciones en el modelo. por cierto: ¿te gustaría esta solicitud como una nueva pregunta? – sgtz

Cuestiones relacionadas