最简单的protobuf-net示例2所需的帮助

问题描述

|| 观察以下代码(从此问题中获取):
  [ProtoContract]
  public class B
  {
    [ProtoMember(1)] public int Y;
  }

  [ProtoContract]
  public class C
  {
    [ProtoMember(1)] public int Y;
  }

  class Program
  {
    static void Main()
    {
      object b = new B { Y = 2 };
      object c = new C { Y = 4 };
      using (var ms = new MemoryStream())
      {
        Serializer.SerializeWithLengthPrefix(ms,b,PrefixStyle.Base128);
        Serializer.SerializeWithLengthPrefix(ms,c,PrefixStyle.Base128);
        ms.Position = 0;
        var b2 = Serializer.DeserializeWithLengthPrefix<B>(ms,PrefixStyle.Base128);
        Debug.Assert(((B)b).Y == b2.Y);
        var c2 = Serializer.DeserializeWithLengthPrefix<C>(ms,PrefixStyle.Base128);
        Debug.Assert(((C)c).Y == c2.Y);
      }
    }
  }
显然,代码是错误的,因为
b
c
被声明为
object
,但是我使用通用的
Serializer.Serialize<T>
方法序列化了它们:
System.ArgumentOutOfRangeException occurred
  Message=Specified argument was out of the range of valid values.
Parameter name: index
  Source=protobuf-net
  ParamName=index
  StackTrace:
       at ProtoBuf.Meta.BasicList.Node.get_Item(Int32 index)
  InnerException: 
如果我将
b
重新声明为
B
,而将
c
重新声明为
C
,则一切正常。但是,我需要将它们声明为
object
,所以我想我必须使用非泛型方法
Serializer.NonGeneric.SerializeWithLengthPrefix
对其进行序列化,这个问题我不理解该方法期望的额外
fieldNumber
参数的含义。有人可以解释一下这是什么,我应该在这里使用它吗? 我使用protobuf-net v2。 谢谢。 编辑 我设法通过添加以下代码使其工作:
RuntimeTypeModel.Default.Add(typeof(object),false).AddSubType(1,typeof(B)).AddSubType(2,typeof(C));
尽管可以工作,但问题是我需要在编译时知道序列化中使用的类型(B = 1,C = 2),这对我来说是不利的。有没有更好的办法? 编辑2 好的,我已经更改了代码,如下所示:
public class GenericSerializationHelper<T> : IGenericSerializationHelper
{
  void IGenericSerializationHelper.SerializeWithLengthPrefix(Stream stream,object obj,PrefixStyle prefixStyle)
  {
    Serializer.SerializeWithLengthPrefix(stream,(T)obj,prefixStyle);
  }
}

public interface IGenericSerializationHelper
{
  void SerializeWithLengthPrefix(Stream stream,PrefixStyle prefixStyle);
}

...

static void Main()
{
  var typeMap = new Dictionary<Type,IGenericSerializationHelper>();
  typeMap[typeof(B)] = new GenericSerializationHelper<B>();
  typeMap[typeof(C)] = new GenericSerializationHelper<C>();

  object b = new B { Y = 2 };
  object c = new C { Y = 4 };
  using (var ms = new MemoryStream())
  {
    typeMap[b.GetType()].SerializeWithLengthPrefix(ms,PrefixStyle.Base128);
    typeMap[c.GetType()].SerializeWithLengthPrefix(ms,PrefixStyle.Base128);
    ms.Position = 0;
    var b2 = Serializer.DeserializeWithLengthPrefix<B>(ms,PrefixStyle.Base128);
    Debug.Assert(((B)b).Y == b2.Y);
    var c2 = Serializer.DeserializeWithLengthPrefix<C>(ms,PrefixStyle.Base128);
    Debug.Assert(((C)c).Y == c2.Y);
  }
}
现在,为了序列化对象,我不需要任何编译时映射,我只需跳转到相应的通用方法即可。当然,我知道在这种方案中,我必须知道反序列化的类型,但这仍然很麻烦。     

解决方法

如果要序列化同类数据,则字段号在很大程度上无关紧要,需要注意的一点是,将其保持为1(又名
Serializer.ListItemTag
),如果需要,可以将其读回列表很简单(但无论哪种方式都非常容易)。 在异类数据的情况下,如本例所示-为此目的设计了一个非通用API(实际上,在v2中,所有API都是非通用的-通用API只是转发给非通用)。通过输入ѭ16,您可以即时告诉它如何解释遇到的任何标签(在流的根处)。如果您选择为给定的标签返回
null
,则它假定您对该对象不感兴趣并完全跳过了该对象(显然,在下面的示例中,它将被炸掉-但这仅仅是因为示例代码很少) :
// I\'m giving the example in terms of the v2 API,because there is a bug in the 
// Serializer.NonGeneric code in the beta - simply,in the first beta cut this
// doesn\'t correctly forward to the type-model. This will be fixed ASAP.
TypeModel model = RuntimeTypeModel.Default;
using (var ms = new MemoryStream())
{
    var tagToType = new Dictionary<int,Type>
    {  // somewhere,we need a registry of what field maps to what Type
        {1,typeof(B)},{2,typeof(C)}
    };
    var typeToTag = tagToType.ToDictionary(pair => pair.Value,pair => pair.Key);

    object b = new B { Y = 2 };
    object c = new C { Y = 4 };
    // in v1,comparable to Serializer.NonGeneric.SerializeWithLengthPrefix(ms,b,PrefixStyle.Base128,typeToTag[b.GetType()]);
    model.SerializeWithLengthPrefix(ms,null,c,typeToTag[c.GetType()]);
    ms.Position = 0;

    // in v1,comparable to Serializer.NonGeneric.TryDeserializeWithLengthPrefix(ms,key => tagToType[key],out b2);
    object b2 = model.DeserializeWithLengthPrefix(ms,key => tagToType[key]);
    object c2 = model.DeserializeWithLengthPrefix(ms,key => tagToType[key]);

    Assert.AreEqual(((B)b).Y,((B)b2).Y);
    Assert.AreEqual(((C)c).Y,((C)c2).Y);
}
    

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...