Protobuf-net Serializing Parent Class 继承对象 属性 标记为 [ProtoIgnore()] 抛出 "No serializer defined for type: System.Object"
Protobuf-net Serializing Parent Class inherited object property marked as [ProtoIgnore()] throwing "No serializer defined for type: System.Object"
我们系统中的所有对象都继承了一个基础 class,它有一个 属性 类型的对象。
我也尝试过将 protoignore 属性添加到基础 class 的所有属性中,但这似乎并不奏效。
class Program
{
static void Main(string[] args)
{
Vehicle vehicle = new Vehicle();
vehicle.BodyStyleDescription = "4x4";
vehicle.BodyStyleText = "Prestige Medium";
dynamic protobufModel = TypeModel.Create();
AddTypeToModel<Vehicle>(protobufModel);
using (MemoryStream compressed = new MemoryStream())
{
using (GZipStream gzip = new GZipStream(compressed, CompressionMode.Compress, true))
{
protobufModel.Serialize(gzip, vehicle);
}
string str = Convert.ToBase64String(compressed.GetBuffer(), 0, Convert.ToInt32(compressed.Length));
}
}
public static MetaType AddTypeToModel<T>(RuntimeTypeModel typeModel)
{
var properties = typeof(T).GetProperties().Select(p => p.Name).OrderBy(name => name);
return typeModel.Add(typeof(T), true).Add(properties.ToArray());
}
}
以下是对象的层次结构
public interface IObjectBaseClass
{
[ProtoIgnore()]
object Parent { get; set; }
[ProtoIgnore()]
bool IsSaved { get; set; }
[ProtoIgnore()]
string XmlAtLoad { get; set; }
}
public class ObjectBaseClass : IObjectBaseClass
{
public ObjectBaseClass()
{
}
[ProtoIgnore()]
internal object _Parent;
[ProtoIgnore()]
internal bool _IsSaved;
[ProtoIgnore()]
internal string _XmlAtLoad;
[ProtoIgnore()]
public bool IsSaved
{
get { return _IsSaved; }
set { _IsSaved = value; }
}
[ProtoIgnore()]
public object Parent
{
get { return _Parent; }
set { _Parent = value; }
}
[ProtoIgnore()]
public string XmlAtLoad
{
get { return _XmlAtLoad; }
set { _XmlAtLoad = value; }
}
}
public class Vehicle : ObjectBaseClass
{
private string _BodyStyleText;
private string _BodyStyleDescription;
public string BodyStyleDescription
{
get { return _BodyStyleDescription; }
set { _BodyStyleDescription = value; }
}
public string BodyStyleText
{
get { return _BodyStyleText; }
set { _BodyStyleText = value; }
}
}
您的问题是,当您执行 typeModel.Add(typeof(T), true).Add(properties.ToArray())
时,您正在将 T
的 所有 属性添加到运行时类型模型,包括那些标有 ProtoIgnore
。您可以通过调用调试方法 protobufModel.GetSchema(typeof(Vehicle))
which returns:
来查看这一点
message Object {
}
message Vehicle {
optional string BodyStyleDescription = 1;
optional string BodyStyleText = 2;
optional bool IsSaved = 3;
optional Object Parent = 4;
optional string XmlAtLoad = 5;
}
要避免添加标有 [ProtoIgnore]
的属性,您可以这样做:
public static MetaType AddTypeToModel<T>(RuntimeTypeModel typeModel)
{
var properties = typeof(T)
.GetProperties()
.Where(p => !p.GetCustomAttributes<ProtoIgnoreAttribute>().Any())
.Select(p => p.Name)
.OrderBy(name => name);
return typeModel.Add(typeof(T), true).Add(properties.ToArray());
}
或者,由于您无论如何都使用 protobuf 属性手动注释某些模型,因此您可以使用 [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
标记派生类型,例如:
[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Vehicle : ObjectBaseClass
{
private string _BodyStyleText;
private string _BodyStyleDescription;
public string BodyStyleDescription
{
get { return _BodyStyleDescription; }
set { _BodyStyleDescription = value; }
}
public string BodyStyleText
{
get { return _BodyStyleText; }
set { _BodyStyleText = value; }
}
}
使用任一方法,Vehicle
的架构变为:
message Vehicle {
optional string BodyStyleDescription = 1;
optional string BodyStyleText = 2;
}
这就是您所需要的。
我们系统中的所有对象都继承了一个基础 class,它有一个 属性 类型的对象。
我也尝试过将 protoignore 属性添加到基础 class 的所有属性中,但这似乎并不奏效。
class Program
{
static void Main(string[] args)
{
Vehicle vehicle = new Vehicle();
vehicle.BodyStyleDescription = "4x4";
vehicle.BodyStyleText = "Prestige Medium";
dynamic protobufModel = TypeModel.Create();
AddTypeToModel<Vehicle>(protobufModel);
using (MemoryStream compressed = new MemoryStream())
{
using (GZipStream gzip = new GZipStream(compressed, CompressionMode.Compress, true))
{
protobufModel.Serialize(gzip, vehicle);
}
string str = Convert.ToBase64String(compressed.GetBuffer(), 0, Convert.ToInt32(compressed.Length));
}
}
public static MetaType AddTypeToModel<T>(RuntimeTypeModel typeModel)
{
var properties = typeof(T).GetProperties().Select(p => p.Name).OrderBy(name => name);
return typeModel.Add(typeof(T), true).Add(properties.ToArray());
}
}
以下是对象的层次结构
public interface IObjectBaseClass
{
[ProtoIgnore()]
object Parent { get; set; }
[ProtoIgnore()]
bool IsSaved { get; set; }
[ProtoIgnore()]
string XmlAtLoad { get; set; }
}
public class ObjectBaseClass : IObjectBaseClass
{
public ObjectBaseClass()
{
}
[ProtoIgnore()]
internal object _Parent;
[ProtoIgnore()]
internal bool _IsSaved;
[ProtoIgnore()]
internal string _XmlAtLoad;
[ProtoIgnore()]
public bool IsSaved
{
get { return _IsSaved; }
set { _IsSaved = value; }
}
[ProtoIgnore()]
public object Parent
{
get { return _Parent; }
set { _Parent = value; }
}
[ProtoIgnore()]
public string XmlAtLoad
{
get { return _XmlAtLoad; }
set { _XmlAtLoad = value; }
}
}
public class Vehicle : ObjectBaseClass
{
private string _BodyStyleText;
private string _BodyStyleDescription;
public string BodyStyleDescription
{
get { return _BodyStyleDescription; }
set { _BodyStyleDescription = value; }
}
public string BodyStyleText
{
get { return _BodyStyleText; }
set { _BodyStyleText = value; }
}
}
您的问题是,当您执行 typeModel.Add(typeof(T), true).Add(properties.ToArray())
时,您正在将 T
的 所有 属性添加到运行时类型模型,包括那些标有 ProtoIgnore
。您可以通过调用调试方法 protobufModel.GetSchema(typeof(Vehicle))
which returns:
message Object { } message Vehicle { optional string BodyStyleDescription = 1; optional string BodyStyleText = 2; optional bool IsSaved = 3; optional Object Parent = 4; optional string XmlAtLoad = 5; }
要避免添加标有 [ProtoIgnore]
的属性,您可以这样做:
public static MetaType AddTypeToModel<T>(RuntimeTypeModel typeModel)
{
var properties = typeof(T)
.GetProperties()
.Where(p => !p.GetCustomAttributes<ProtoIgnoreAttribute>().Any())
.Select(p => p.Name)
.OrderBy(name => name);
return typeModel.Add(typeof(T), true).Add(properties.ToArray());
}
或者,由于您无论如何都使用 protobuf 属性手动注释某些模型,因此您可以使用 [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
标记派生类型,例如:
[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Vehicle : ObjectBaseClass
{
private string _BodyStyleText;
private string _BodyStyleDescription;
public string BodyStyleDescription
{
get { return _BodyStyleDescription; }
set { _BodyStyleDescription = value; }
}
public string BodyStyleText
{
get { return _BodyStyleText; }
set { _BodyStyleText = value; }
}
}
使用任一方法,Vehicle
的架构变为:
message Vehicle { optional string BodyStyleDescription = 1; optional string BodyStyleText = 2; }
这就是您所需要的。