通过 C# 和 Java 之间的 protobuf-net 进行序列化/解封
Posted
技术标签:
【中文标题】通过 C# 和 Java 之间的 protobuf-net 进行序列化/解封【英文标题】:Serialization / Desealization via protobuf-net between C# and Java 【发布时间】:2021-10-20 11:23:46 【问题描述】:我有 2 个应用程序在两者之间使用 protobuf。第一个(C#)使用带有可序列化对象 VisualSettings 的 protobuf-net:
[ProtoContract]
public class VisualSettings
[ProtoContract]
public class BodyPartHolder
[ProtoMember(1)]
public BodyPartType type;
[ProtoMember(2)]
public int id;
public BodyPartHolder()
public BodyPartHolder(BodyPartType type, int id)
this.type = type;
this.id = id;
public BodyPartHolder Copy()
return new BodyPartHolder(type, id);
public interface IPaintHolder
int id get; set;
public interface ICustomPaintHolder
HSBColor hsb get; set;
[ProtoContract]
[ProtoInclude(100, typeof(BaseBodyPaintHolder)), ProtoInclude(200, typeof(BaseWheelPaintHolder)), ProtoInclude(300, typeof(BaseGlassPaintHolder))]
[ProtoInclude(400, typeof(BaseSmokePaintHolder)), ProtoInclude(500, typeof(BaseSuspensionPaintHolder)), ProtoInclude(600, typeof(BaseInteriorPaintHolder))]
public abstract class BasePaintHolder
[JsonIgnore]
public bool isCustom => this is ICustomPaintHolder;
[JsonIgnore]
public string materialName => CarPaintMaterials.GetName(material);
[JsonIgnore]
public CarPaintType material => materials[materialId];
[ProtoMember(1)]
public int materialId;
protected abstract CarPaintType[] materials get;
public BasePaintHolder()
public BasePaintHolder(int materialId)
this.materialId = materialId;
public virtual float GetCategoryCostCoefficient(CarSharedMeta carMeta)
return BasePaintItem.DefaultCostCoefficient;
public float GetMaterialCostCoefficient(CarSharedMeta carMeta)
return carMeta.GetPaintMaterialCostCoefficient(material);
public abstract bool Equals(BasePaintHolder other);
[ProtoContract]
[ProtoInclude(100, typeof(BodyPaintHolder)), ProtoInclude(200, typeof(BodyCustomPaintHolder))]
public abstract class BaseBodyPaintHolder : BasePaintHolder
[ProtoMember(1)]
public BodyPartType part;
protected override CarPaintType[] materials => CarPaintMaterials.Body;
public BaseBodyPaintHolder()
public BaseBodyPaintHolder(BodyPartType part, int materialId) : base(materialId)
this.part = part;
public override float GetCategoryCostCoefficient(CarSharedMeta carMeta)
return carMeta.GetPaintCategoryCostCoefficient(part);
public abstract BaseBodyPaintHolder Copy();
[ProtoContract]
public class BodyPaintHolder : BaseBodyPaintHolder, IPaintHolder
[ProtoMember(1)]
public int id get; set;
public BodyPaintHolder()
public BodyPaintHolder(BodyPartType part, int materialId, int id) : base(part, materialId)
this.id = id;
public override BaseBodyPaintHolder Copy()
return new BodyPaintHolder(part, materialId, id);
public override bool Equals(BasePaintHolder other)
var otherPaint = other as BodyPaintHolder;
return (otherPaint != null) && (otherPaint.part == part) && (otherPaint.materialId == materialId) && (otherPaint.id == id);
[ProtoContract]
public class BodyCustomPaintHolder : BaseBodyPaintHolder, ICustomPaintHolder
[ProtoMember(1)]
public HSBColor hsb get; set;
public BodyCustomPaintHolder()
public BodyCustomPaintHolder(BodyPartType part, int materialId, HSBColor hsb) : base(part, materialId)
this.hsb = hsb;
public override BaseBodyPaintHolder Copy()
return new BodyCustomPaintHolder(part, materialId, hsb);
public override bool Equals(BasePaintHolder other)
var otherPaint = other as BodyCustomPaintHolder;
return (otherPaint != null) && (otherPaint.part == part) && (otherPaint.materialId == materialId) && HSBColor.EqualsOpaque(otherPaint.hsb, hsb);
[ProtoContract]
[ProtoInclude(100, typeof(WheelPaintHolder)), ProtoInclude(200, typeof(WheelCustomPaintHolder))]
public abstract class BaseWheelPaintHolder : BasePaintHolder
[ProtoMember(1)]
public WheelPaintPart part;
protected override CarPaintType[] materials => CarPaintMaterials.Wheel;
public BaseWheelPaintHolder()
public BaseWheelPaintHolder(WheelPaintPart part, int materialId) : base(materialId)
this.part = part;
public abstract BaseWheelPaintHolder Copy();
[ProtoContract]
public class WheelPaintHolder : BaseWheelPaintHolder, IPaintHolder
[ProtoMember(1)]
public int id get; set;
public WheelPaintHolder()
public WheelPaintHolder(WheelPaintPart part, int materialId, int id) : base(part, materialId)
this.id = id;
public override BaseWheelPaintHolder Copy()
return new WheelPaintHolder(part, materialId, id);
public override bool Equals(BasePaintHolder other)
var otherPaint = other as WheelPaintHolder;
return (otherPaint != null) && (otherPaint.part == part) && (otherPaint.materialId == materialId) && (otherPaint.id == id);
[ProtoContract]
public class WheelCustomPaintHolder : BaseWheelPaintHolder, ICustomPaintHolder
[ProtoMember(1)]
public HSBColor hsb get; set;
public WheelCustomPaintHolder()
public WheelCustomPaintHolder(WheelPaintPart part, int materialId, HSBColor hsb) : base(part, materialId)
this.hsb = hsb;
public override BaseWheelPaintHolder Copy()
return new WheelCustomPaintHolder(part, materialId, hsb);
public override bool Equals(BasePaintHolder other)
var otherPaint = other as WheelCustomPaintHolder;
return (otherPaint != null) && (otherPaint.part == part) && (otherPaint.materialId == materialId) && HSBColor.EqualsOpaque(otherPaint.hsb, hsb);
[ProtoContract]
[ProtoInclude(100, typeof(GlassPaintHolder)), ProtoInclude(200, typeof(GlassCustomPaintHolder))]
public abstract class BaseGlassPaintHolder : BasePaintHolder
[ProtoMember(1)]
public GlassPaintPart part get; set;
protected override CarPaintType[] materials => CarPaintMaterials.Glass;
public BaseGlassPaintHolder()
public BaseGlassPaintHolder(GlassPaintPart part, int materialId) : base(materialId)
this.part = part;
public abstract BaseGlassPaintHolder Copy();
[ProtoContract]
public class GlassPaintHolder : BaseGlassPaintHolder, IPaintHolder
[ProtoMember(1)]
public int id get; set;
public GlassPaintHolder()
public GlassPaintHolder(GlassPaintPart part, int materialId, int id) : base(part, materialId)
this.id = id;
public override BaseGlassPaintHolder Copy()
return new GlassPaintHolder(part, materialId, id);
public override bool Equals(BasePaintHolder other)
var otherPaint = other as GlassPaintHolder;
return (otherPaint != null) && (otherPaint.materialId == materialId) && (otherPaint.id == id);
[ProtoContract]
public class GlassCustomPaintHolder : BaseGlassPaintHolder, ICustomPaintHolder
[ProtoMember(1)]
public HSBColor hsb get; set;
public GlassCustomPaintHolder()
public GlassCustomPaintHolder(GlassPaintPart part, int materialId, HSBColor hsb) : base(part, materialId)
this.hsb = hsb;
public override BaseGlassPaintHolder Copy()
return new GlassCustomPaintHolder(part, materialId, hsb);
public override bool Equals(BasePaintHolder other)
var otherPaint = other as GlassCustomPaintHolder;
return (otherPaint != null) && (otherPaint.materialId == materialId) && HSBColor.EqualsOpaque(otherPaint.hsb, hsb);
[ProtoContract]
[ProtoInclude(100, typeof(SmokePaintHolder)), ProtoInclude(200, typeof(SmokeCustomPaintHolder))]
public abstract class BaseSmokePaintHolder : BasePaintHolder
protected override CarPaintType[] materials => CarPaintMaterials.Smoke;
public BaseSmokePaintHolder()
public BaseSmokePaintHolder(int materialId) : base(materialId)
public abstract BaseSmokePaintHolder Copy();
[ProtoContract]
public class SmokePaintHolder : BaseSmokePaintHolder, IPaintHolder
[ProtoMember(1)]
public int id get; set;
public SmokePaintHolder()
public SmokePaintHolder(int materialId, int id) : base(materialId)
this.id = id;
public override BaseSmokePaintHolder Copy()
return new SmokePaintHolder(materialId, id);
public override bool Equals(BasePaintHolder other)
var otherPaint = other as SmokePaintHolder;
return (otherPaint != null) && (otherPaint.materialId == materialId) && (otherPaint.id == id);
[ProtoContract]
public class SmokeCustomPaintHolder : BaseSmokePaintHolder, ICustomPaintHolder
[ProtoMember(1)]
public HSBColor hsb get; set;
public SmokeCustomPaintHolder()
public SmokeCustomPaintHolder(int materialId, HSBColor hsb) : base(materialId)
this.hsb = hsb;
public override BaseSmokePaintHolder Copy()
return new SmokeCustomPaintHolder(materialId, hsb);
public override bool Equals(BasePaintHolder other)
var otherPaint = other as SmokeCustomPaintHolder;
return (otherPaint != null) && (otherPaint.materialId == materialId) && HSBColor.EqualsOpaque(otherPaint.hsb, hsb);
[ProtoContract]
[ProtoInclude(100, typeof(SuspensionPaintHolder)), ProtoInclude(200, typeof(SuspensionCustomPaintHolder))]
public abstract class BaseSuspensionPaintHolder : BasePaintHolder
[ProtoMember(1)]
public SuspensionPaintPart part get; set;
protected override CarPaintType[] materials => CarPaintMaterials.Suspension;
public BaseSuspensionPaintHolder()
public BaseSuspensionPaintHolder(SuspensionPaintPart part, int materialId) : base(materialId)
this.part = part;
public override float GetCategoryCostCoefficient(CarSharedMeta carMeta)
return carMeta.GetPaintCategoryCostCoefficient(BodyPartType.Suspension);
public abstract BaseSuspensionPaintHolder Copy();
[ProtoContract]
public class SuspensionPaintHolder : BaseSuspensionPaintHolder, IPaintHolder
[ProtoMember(1)]
public int id get; set;
public SuspensionPaintHolder()
public SuspensionPaintHolder(SuspensionPaintPart part, int id, int materialId) : base(part, materialId)
this.id = id;
public override BaseSuspensionPaintHolder Copy()
return new SuspensionPaintHolder(part, id, materialId);
public override bool Equals(BasePaintHolder other)
var otherPaint = other as SuspensionPaintHolder;
return (otherPaint != null) && (otherPaint.materialId == materialId) && (otherPaint.id == id);
[ProtoContract]
public class SuspensionCustomPaintHolder : BaseSuspensionPaintHolder, ICustomPaintHolder
[ProtoMember(1)]
public HSBColor hsb get; set;
public SuspensionCustomPaintHolder()
public SuspensionCustomPaintHolder(SuspensionPaintPart part, HSBColor hsb, int materialId) : base(part, materialId)
this.hsb = hsb;
public override BaseSuspensionPaintHolder Copy()
return new SuspensionCustomPaintHolder(part, hsb, materialId);
public override bool Equals(BasePaintHolder other)
var otherPaint = other as SuspensionCustomPaintHolder;
return (otherPaint != null) && (otherPaint.materialId == materialId) && HSBColor.EqualsOpaque(otherPaint.hsb, hsb);
[ProtoContract]
[ProtoInclude(100, typeof(InteriorPaintHolder)), ProtoInclude(200, typeof(InteriorCustomPaintHolder))]
public abstract class BaseInteriorPaintHolder : BasePaintHolder
[ProtoMember(1)]
public InteriorPaintPart part get; set;
protected override CarPaintType[] materials => CarPaintMaterials.Interior;
public BaseInteriorPaintHolder()
public BaseInteriorPaintHolder(InteriorPaintPart part, int materialId) : base(materialId)
this.part = part;
public override float GetCategoryCostCoefficient(CarSharedMeta carMeta)
return carMeta.GetPaintCategoryCostCoefficient(BodyPartType.SeatLeft);
public abstract BaseInteriorPaintHolder Copy();
[ProtoContract]
public class InteriorPaintHolder : BaseInteriorPaintHolder, IPaintHolder
[ProtoMember(1)]
public int id get; set;
public InteriorPaintHolder()
public InteriorPaintHolder(InteriorPaintPart part, int id, int materialId) : base(part, materialId)
this.id = id;
public override BaseInteriorPaintHolder Copy()
return new InteriorPaintHolder(part, id, materialId);
public override bool Equals(BasePaintHolder other)
return (other is InteriorPaintHolder otherPaint) && (otherPaint.materialId == materialId) && (otherPaint.id == id);
[ProtoContract]
public class InteriorCustomPaintHolder : BaseInteriorPaintHolder, ICustomPaintHolder
[ProtoMember(1)]
public HSBColor hsb get; set;
public InteriorCustomPaintHolder()
public InteriorCustomPaintHolder(InteriorPaintPart part, HSBColor hsb, int materialId) : base(part, materialId)
this.hsb = hsb;
public override BaseInteriorPaintHolder Copy()
return new InteriorCustomPaintHolder(part, hsb, materialId);
public override bool Equals(BasePaintHolder other)
return (other is InteriorCustomPaintHolder otherPaint) && (otherPaint.materialId == materialId) && HSBColor.EqualsOpaque(otherPaint.hsb, hsb);
[ProtoContract]
[ProtoInclude(100, typeof(GenericPaintHolder)), ProtoInclude(200, typeof(GenericCustomPaintHolder))]
public abstract class BaseGenericPaintHolder : BasePaintHolder
protected override CarPaintType[] materials => CarPaintMaterials.Generic;
public BaseGenericPaintHolder()
public BaseGenericPaintHolder(int materialId) : base(materialId)
public abstract BaseGenericPaintHolder Copy();
[ProtoContract]
public class GenericPaintHolder : BaseGenericPaintHolder, IPaintHolder
[ProtoMember(1)]
public int id get; set;
public GenericPaintHolder()
public GenericPaintHolder(int materialId, int id) : base(materialId)
this.id = id;
public override BaseGenericPaintHolder Copy()
return new GenericPaintHolder(materialId, id);
public override bool Equals(BasePaintHolder other)
var otherPaint = other as GenericPaintHolder;
return (otherPaint != null) && (otherPaint.materialId == materialId) && (otherPaint.id == id);
[ProtoContract]
public class GenericCustomPaintHolder : BaseGenericPaintHolder, ICustomPaintHolder
[ProtoMember(1)]
public HSBColor hsb get; set;
public GenericCustomPaintHolder()
public GenericCustomPaintHolder(int materialId, HSBColor hsb) : base(materialId)
this.hsb = hsb;
public override BaseGenericPaintHolder Copy()
return new GenericCustomPaintHolder(materialId, hsb);
public override bool Equals(BasePaintHolder other)
var otherPaint = other as GenericCustomPaintHolder;
return (otherPaint != null) && (otherPaint.materialId == materialId) && HSBColor.EqualsOpaque(otherPaint.hsb, hsb);
[ProtoMember(1)]
public List<BaseBodyPaintHolder> bodyPaints = null;
[ProtoMember(2)]
public List<BaseWheelPaintHolder> frontWheelPaints = null;
[ProtoMember(3)]
public List<BaseWheelPaintHolder> rearWheelPaints = null;
[ProtoMember(4)]
public List<BaseSuspensionPaintHolder> suspensionPaints = null;
[ProtoMember(5)]
public BaseGlassPaintHolder glassPaint = null;
[ProtoMember(6)]
public BaseSmokePaintHolder smokePaint = null;
[ProtoMember(14)]
public BaseGenericPaintHolder genericPaint = null;
[ProtoMember(15)]
public List<BaseInteriorPaintHolder> interiorPaints = null;
[ProtoMember(16)]
public List<BaseGlassPaintHolder> lightGlassesPaints = null;
[ProtoMember(7)]
public Dictionary<WheelAxles, int> wheelTires = null;
[ProtoMember(8)]
public List<BodyPartHolder> bodyParts = null;
[ProtoMember(9)]
public int frontRimPartId = 1;
[ProtoMember(10)]
public int rearRimPartId = 1;
[ProtoMember(11)]
public int bodyKitId;
[ProtoMember(12)]
public List<VinylLayer> vinylLayers = null;
[ProtoMember(13)]
public string workshopItemId = null;
public VisualSettings()
bodyPaints = new List<BaseBodyPaintHolder>();
rearWheelPaints = new List<BaseWheelPaintHolder>();
frontWheelPaints = new List<BaseWheelPaintHolder>();
suspensionPaints = new List<BaseSuspensionPaintHolder>();
interiorPaints = new List<BaseInteriorPaintHolder>();
lightGlassesPaints = new List<BaseGlassPaintHolder>();
bodyParts = new List<BodyPartHolder>();
vinylLayers = new List<VinylLayer>();
wheelTires = new Dictionary<WheelAxles, int>();
public VisualSettings(VisualSettings copyFrom)
bodyPaints = new List<BaseBodyPaintHolder>(copyFrom.bodyPaints);
rearWheelPaints = new List<BaseWheelPaintHolder>(copyFrom.rearWheelPaints);
frontWheelPaints = new List<BaseWheelPaintHolder>(copyFrom.frontWheelPaints);
suspensionPaints = new List<BaseSuspensionPaintHolder>(copyFrom.suspensionPaints);
interiorPaints = new List<BaseInteriorPaintHolder>(copyFrom.interiorPaints);
lightGlassesPaints = new List<BaseGlassPaintHolder>(copyFrom.lightGlassesPaints);
bodyParts = new List<BodyPartHolder>(copyFrom.bodyParts);
vinylLayers = new List<VinylLayer>(copyFrom.vinylLayers);
wheelTires = new Dictionary<WheelAxles, int>(copyFrom.wheelTires);
glassPaint = copyFrom.glassPaint;
smokePaint = copyFrom.smokePaint;
genericPaint = copyFrom.genericPaint;
frontRimPartId = copyFrom.frontRimPartId;
rearRimPartId = copyFrom.rearRimPartId;
bodyKitId = copyFrom.bodyKitId;
workshopItemId = copyFrom.workshopItemId;
我通过Serializer.GetProto<VisualSettings>()
生成了 .proto 文件,并使用该 .proto 文件生成了 Java 类(用于第二个应用程序)。
protobuf-net 生成的 proto 文件:
syntax = "proto2";
package visual_settings;
option java_multiple_files = true;
option java_package = "com.test";
option java_outer_classname = "VisualSettingsProto";
message BaseBodyPaintHolder
optional BodyPartType part = 1 [default = Chassis];
// the following represent sub-types; at most 1 should have a value
optional BodyPaintHolder BodyPaintHolder = 100;
optional BodyCustomPaintHolder BodyCustomPaintHolder = 200;
message BaseGenericPaintHolder
// the following represent sub-types; at most 1 should have a value
optional GenericPaintHolder GenericPaintHolder = 100;
optional GenericCustomPaintHolder GenericCustomPaintHolder = 200;
message BaseGlassPaintHolder
optional GlassPaintPart part = 1 [default = Glasses];
// the following represent sub-types; at most 1 should have a value
optional GlassPaintHolder GlassPaintHolder = 100;
optional GlassCustomPaintHolder GlassCustomPaintHolder = 200;
message BaseInteriorPaintHolder
optional InteriorPaintPart part = 1 [default = SteeringWheelAlcantar];
// the following represent sub-types; at most 1 should have a value
optional InteriorPaintHolder InteriorPaintHolder = 100;
optional InteriorCustomPaintHolder InteriorCustomPaintHolder = 200;
message BasePaintHolder
optional int32 materialId = 1 [default = 0];
// the following represent sub-types; at most 1 should have a value
optional BaseBodyPaintHolder BaseBodyPaintHolder = 100;
optional BaseWheelPaintHolder BaseWheelPaintHolder = 200;
optional BaseGlassPaintHolder BaseGlassPaintHolder = 300;
optional BaseSmokePaintHolder BaseSmokePaintHolder = 400;
optional BaseSuspensionPaintHolder BaseSuspensionPaintHolder = 500;
optional BaseInteriorPaintHolder BaseInteriorPaintHolder = 600;
message BaseSmokePaintHolder
// the following represent sub-types; at most 1 should have a value
optional SmokePaintHolder SmokePaintHolder = 100;
optional SmokeCustomPaintHolder SmokeCustomPaintHolder = 200;
message BaseSuspensionPaintHolder
optional SuspensionPaintPart part = 1 [default = Arm];
// the following represent sub-types; at most 1 should have a value
optional SuspensionPaintHolder SuspensionPaintHolder = 100;
optional SuspensionCustomPaintHolder SuspensionCustomPaintHolder = 200;
message BaseWheelPaintHolder
optional WheelPaintPart part = 1 [default = SpokeFront];
// the following represent sub-types; at most 1 should have a value
optional WheelPaintHolder WheelPaintHolder = 100;
optional WheelCustomPaintHolder WheelCustomPaintHolder = 200;
message BodyCustomPaintHolder
optional HSBColor hsb = 1;
message BodyPaintHolder
optional int32 id = 1 [default = 0];
message BodyPartHolder
optional BodyPartType type = 1 [default = Chassis];
optional int32 id = 2 [default = 0];
enum BodyPartType
Chassis = 0;
BumperFront = 1;
BumperRear = 2;
Skirts = 3;
Doors = 4;
Roof = 5;
Mirrors = 6;
Bonnet = 7;
Trunk = 8;
Spoiler = 9;
LightsFront = 10;
LightsRear = 11;
Exhaust = 12;
Cage = 13;
Suspension = 14;
Interior = 15;
SeatLeft = 16;
SeatRight = 17;
SteeringWheel = 18;
Handbrake = 19;
Shifter = 20;
Dashboard = 21;
Engine = 22;
BlobShadow = 23;
message GenericCustomPaintHolder
optional HSBColor hsb = 1;
message GenericPaintHolder
optional int32 id = 1 [default = 0];
message GlassCustomPaintHolder
optional HSBColor hsb = 1;
message GlassPaintHolder
optional int32 id = 1 [default = 0];
enum GlassPaintPart
Glasses = 0;
FrontLight = 1;
RearLight = 2;
FogLight = 3;
message HSBColor
optional float h = 1 [default = 0];
optional float s = 2 [default = 0];
optional float b = 3 [default = 0];
optional float a = 4 [default = 0];
message InteriorCustomPaintHolder
optional HSBColor hsb = 1;
message InteriorPaintHolder
optional int32 id = 1 [default = 0];
enum InteriorPaintPart
SteeringWheelAlcantar = 0;
SteeringWheelStrings = 1;
SteeringWheelSpokes = 2;
LeftSeatBase = 3;
LeftSeatBottom = 4;
RightSeatBase = 5;
RightSeatBottom = 6;
GearBoxHandle = 7;
HandbrakeHandle = 8;
message KeyValuePair_WheelAxles_Int32
optional WheelAxles Key = 1;
optional int32 Value = 2;
message SmokeCustomPaintHolder
optional HSBColor hsb = 1;
message SmokePaintHolder
optional int32 id = 1 [default = 0];
message SuspensionCustomPaintHolder
optional HSBColor hsb = 1;
message SuspensionPaintHolder
optional int32 id = 1 [default = 0];
enum SuspensionPaintPart
Arm = 0;
Rack = 1;
Spring = 2;
BrakeCaliper = 3;
message VinylLayerSurrogate
optional int32 rawId = 1 [default = 0];
optional float angle = 2 [default = 0];
optional bool isSymmetry = 3 [default = false];
optional bool isHorizontalFlip = 4 [default = false];
optional bool isVerticalFlip = 5 [default = false];
optional bool isPassThrough = 6 [default = false];
optional bytes colors = 7;
optional bytes transform = 8;
optional int32 groupMask = 9 [default = 0];
optional float clipMaskShift = 10 [default = 0];
message VisualSettings
repeated BasePaintHolder bodyPaints = 1;
repeated BasePaintHolder frontWheelPaints = 2;
repeated BasePaintHolder rearWheelPaints = 3;
repeated BasePaintHolder suspensionPaints = 4;
optional BasePaintHolder glassPaint = 5;
optional BasePaintHolder smokePaint = 6;
repeated KeyValuePair_WheelAxles_Int32 wheelTires = 7;
repeated BodyPartHolder bodyParts = 8;
optional int32 frontRimPartId = 9 [default = 0];
optional int32 rearRimPartId = 10 [default = 0];
optional int32 bodyKitId = 11 [default = 0];
repeated VinylLayerSurrogate vinylLayers = 12;
optional string workshopItemId = 13;
optional BaseGenericPaintHolder genericPaint = 14;
repeated BasePaintHolder interiorPaints = 15;
repeated BasePaintHolder lightGlassesPaints = 16;
enum WheelAxles
Front = 0;
Rear = 1;
message WheelCustomPaintHolder
optional HSBColor hsb = 1;
message WheelPaintHolder
optional int32 id = 1 [default = 0];
enum WheelPaintPart
SpokeFront = 0;
SpokeRear = 1;
RimFront = 2;
RimRear = 3;
使用生成的 java 类,我可以毫无问题地从 C# 反序列化数据,但是当我在 Java 端序列化数据 (VisualSetting) 时,C# 无法反序列化它,我收到错误:
ProtoException: No parameterless constructor found for BasePaintHolder
。
但是java可以反序列化自己的序列化数据。
我怀疑,protobuf-net 生成的 .proto 模板的方式不正确。我可以改进我的 .proto 文件吗?还是我做错了什么?
【问题讨论】:
我认为多态性支持是一种扩展,我不确定 Java 对它的支持程度。希望 Marc Gravell 能看到这一点并提供更多详细信息。 @JonasH 不,他们非常不可靠,几乎从不回答问题 【参考方案1】:这是因为继承,基本上;继承不是protobuf直接支持的概念,所以protobuf-net通过嵌套子对象对继承进行建模;为了避免一些复杂性,当序列化这个时,protobuf-net 总是从编写继承部分开始 first - 所以:当序列化BasePaintHolder
时,它可能会序列化字段 400(@987654323 的子类型数据@),然后字段 1 (materialId
)。这意味着在反序列化的时候,它有一个明显的构造路径,即在它获取到field数据的时候,它已经构造了最终的具体类型。
这很好,对于 protobuf-net 到 protobuf-net 的场景,但是当我们在 Java 中处理相同的数据时,它不知道也不关心这一点,并选择按字段升序进行序列化,即字段 1 ,然后是字段 400。规范中明确指出字段可能乱序,但 Java 可以选择做任何它想做的事情。
所以:现在我们将这些数据带回 protobuf-net,我们看到字段 1first;那时,我们不知道最终的类型是什么,也无处(还)粘贴数据。由于没有更好的选择,库尝试使用基本类型 BasePaintHolder
作为占位符,直到它可以做出更好的决定,但事实证明这种类型是 abstract
,所以:即使这样也失败了.
所以:这就是 为什么,以及一些背景故事。我们能做什么?
嗯,我们可以尝试的第一件事可能是删除abstract
,使其在技术上可构造。为防止外部代码意外创建实例,您还可以将构造函数设为protected
、internal
或private protected
(即protected
和internal
的交集)。我们也可以尝试在[ProtoContract]
上使用SkipConstructor=true
修饰符。
如果这不起作用:可能需要基本上使用 2 个不同的对象模型;一个很简单——本质上更像 Java 版本,可能是通过https://protogen.marcgravell.com/ 运行你的模式——一个具有继承性;使用简单版本进行反序列化(以及可选的序列化,尽管这无关紧要),然后将您自己代码中的数据重新映射到实际模型。另一个选择是让我想出一种神奇而自动的方法。其中:不是一项小工作。
【讨论】:
谢谢!删除抽象类的方法效果很好。以上是关于通过 C# 和 Java 之间的 protobuf-net 进行序列化/解封的主要内容,如果未能解决你的问题,请参考以下文章
google protobuf可以用于android中C和Java服务之间的通信吗?