Gua*_*anX 5 c# serialization protobuf-net
假设我有以下课程:
public class Test {
int x { get; set; }
int y { get; set; }
Vector3 coords { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
如果我不能在来自外部程序集的类上使用[ProtoContract]和[ProtoMember(x)]属性,我该如何序列化这个对象Vector3。
我已阅读如何使用 protobuf-net 或其他序列化程序序列化 3rd 方类型?但它很模糊(例如,我不知道是否可以混合使用 TypeModel 和属性方法,或者如果我选择仅使用 TypeModel 方法等,如何将未知类型成员作为字段添加到已知类型成员中),所以我需要我的情况的一个具体例子。
例如,我像这样声明 TypeModel:
RuntimeTypeModel.Default.Add(typeof(Vector3), false).Add(1, "x").Add(2, "y").Add(3, "z");
RuntimeTypeModel.Default.Add(typeof(SerializableTestClass), false).Add(1, "_x").Add(2, "_y").Add(3, "_coords");
Run Code Online (Sandbox Code Playgroud)
序列化/反序列化:
if (GUILayout.Button("Serialize")) {
SerializableTestClass testClass = new SerializableTestClass();
testClass.changeMembers();
RuntimeTypeModel.Default.Serialize(_serializedObject, testClass);
}
if (GUILayout.Button("Deserialize")) {
SerializableTestClass test = (SerializableTestClass) RuntimeTypeModel.Default.Deserialize(_serializedObject, null, typeof(SerializableTestClass));
Debug.Log("Deserialized object: " + test.ToString());
}
Run Code Online (Sandbox Code Playgroud)
当我尝试序列化时,出现错误:
InvalidOperationException: Duplicate field-number detected; 1 on: SerializableTestClass
Run Code Online (Sandbox Code Playgroud)
更新 ============================
现在,我更改了代码,使一切看起来像这样: Serializable 类:
[ProtoContract]
public class SerializableTestClass {
[ProtoMember(1)]
int _x { get; set; }
[ProtoMember(2)]
int _y { get; set; }
[ProtoMember(3)]
Vector3 _coords { get; set; }
public SerializableTestClass() {
Debug.Log("SerializableTestClass.ctor()");
_x = 10;
_y = 20;
_coords = Vector2.one * 2;
}
public void changeMembers() {
_x += -3;
_y += 134;
_coords *= 3;
}
public override string ToString() {
return _x.ToString() + " " + _y + " " + _coords;
}
}
Run Code Online (Sandbox Code Playgroud)
模型:
_model = TypeModel.Create();
_model.Add(typeof(Vector3), false).Add(1, "x").Add(2, "y").Add(3, "z");
_model.Add(typeof(SerializableTestClass), true);
Run Code Online (Sandbox Code Playgroud)
序列化/反序列化:
if (GUILayout.Button("Serialize")) {
SerializableTestClass testClass = new SerializableTestClass();
_serializedObject = new MemoryStream();
testClass.changeMembers();
_model.Serialize(_serializedObject, testClass);
}
if (GUILayout.Button("Deserialize")) {
SerializableTestClass test = (SerializableTestClass) _model.Deserialize(_serializedObject, null, typeof(SerializableTestClass));
Debug.Log("Deserialized object: " + test.ToString());
}
Run Code Online (Sandbox Code Playgroud)
输出: 10 20 (2.0, 2.0, 2.0)
应该: 7 154 (6.0, 6.0, 6.0)
这听起来很愚蠢,但以下是我意外重现此内容的方法:检查您ProtoContractAttribute在本地没有自己定义的;基本上,检查当您将光标放在上面[ProtoContract]然后按f12或右键单击并转到显示定义时会发生什么。你应该看到的是这样的:

但是,在解析类型时,您可能不小心选择了“在(...各种选项...)中为'ProtoContract'生成类” - 如果您实际上没有引用,那么这很容易完成时间,只需按ctrl+ .,enter(添加用途的快速方法)。这会生成一个如下文件:
using System;
internal class ProtoContractAttribute : Attribute
{
}
Run Code Online (Sandbox Code Playgroud)
这里重要的一点是它位于错误的命名空间中,因此 protobuf-net 不会将其视为相关属性。
所以:如果你像我一样笨拙,这可能就是原因......
不相关,但如果构造函数中有非默认值,则可能应该在反序列化期间跳过构造函数;你通过以下方式做到这一点:
[ProtoContract(SkipConstructor=true)]
Run Code Online (Sandbox Code Playgroud)
以下是我使用常规 .NET 和伪造的模型Vector3;它工作正常:
using ProtoBuf;
using ProtoBuf.Meta;
using System;
using System.IO;
[ProtoContract(SkipConstructor=true)]
public class SerializableTestClass
{
[ProtoMember(1)]
int _x { get; set; }
[ProtoMember(2)]
int _y { get; set; }
[ProtoMember(3)]
Vector3 _coords { get; set; }
public SerializableTestClass()
{
_x = 10;
_y = 20;
_coords = Vector3.one * 2;
}
public void changeMembers()
{
_x += -3;
_y += 134;
_coords *= 3;
}
public override string ToString()
{
return _x.ToString() + " " + _y + " " + _coords;
}
}
struct Vector3
{
public int x, y, z;
public static Vector3 one = new Vector3 { x = 1, y = 1, z = 1 };
public static Vector3 operator *(Vector3 value, int times)
{
return new Vector3
{
x = value.x * times,
y = value.y * times,
z = value.z * times
};
}
public override string ToString()
{
return string.Format("({0}, {1}, {2})", x, y, z);
}
}
class Program
{
static RuntimeTypeModel _model;
static void Main()
{
_model = TypeModel.Create();
_model.Add(typeof(Vector3), false).Add(1, "x").Add(2, "y").Add(3, "z");
_model.Add(typeof(SerializableTestClass), true);
SerializableTestClass testClass = new SerializableTestClass();
var _serializedObject = new MemoryStream();
testClass.changeMembers();
Console.WriteLine("Original object: " + testClass.ToString());
_model.Serialize(_serializedObject, testClass);
_serializedObject.Position = 0;
Console.WriteLine(_serializedObject.Length);
SerializableTestClass test = (SerializableTestClass)_model.Deserialize(_serializedObject, null, typeof(SerializableTestClass));
Console.WriteLine("Deserialized object: " + test.ToString());
}
}
Run Code Online (Sandbox Code Playgroud)