请看以下代码(取自此问题):
[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 被声明为对象,但我使用通用的
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, object obj, 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, b, PrefixStyle.Base128);
typeMap[c.GetType()].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);
}
}
现在,为了序列化对象,我不需要任何编译时映射,只需跳转到相应的通用方法。当然,我知道在这个方案中,在反序列化时必须知道类型,这仍然是个问题。