我正在尝试将一个C#类序列化为protobuf格式,该类具有特定于域的类型的属性。但是这些类型应该作为值类型处理。
我正在使用protobuf.net。
这是一个例子
[ProtoContract]
public class TestClass
{
[ProtoMember(1)]
public string StringProperty { get; set; }
[ProtoMember(2)]
public DomainTypeToBeHandldedAsString DomainTypeToBeHandldedAsString { get; set; }
}
public class DomainTypeToBeHandldedAsString
{
public string Value { get; set; }
public static implicit operator string(DomainTypeToBeHandldedAsString domainType)
{
return domainType?.Value;
}
public static implicit operator DomainTypeToBeHandldedAsString(string s)
{
return new DomainTypeToBeHandldedAsString {Value = s};
}
}
在序列化消息中,我不希望人们关心DomainTypeToBeHandldedAsString。我只是希望他们看到一个字符串并发送一个字符串。
所以我试着这样做:
var model = ProtoBuf.Meta.RuntimeTypeModel.Default;
model.Add(typeof(DomainTypeToBeHandldedAsString), false).SetSurrogate(typeof(string));
但是这个例外失败了:
System.ArgumentException: 'Repeated data (a list, collection, etc) has inbuilt behaviour and cannot be used as a surrogate'
有没有办法为这样的类指定自定义序列化程序?应该说,还有一些域类型应该被视为int或其他值类型。所以不仅仅是字符串。
由于
修改
我另外尝试了这个:
[ProtoContract]
public class TestClass
{
[ProtoMember(1)]
public string StringProperty { get; set; }
public DomainTypeToBeHandldedAsInt DomainTypeToBeHandldedAsInt { get; set; }
}
[ProtoContract]
public class DomainTypeToBeHandldedAsInt : IConvertible
{
[ProtoMember(1)]
public int Value { get; set; }
public static implicit operator int(DomainTypeToBeHandldedAsInt domainType)
{
return domainType?.Value ?? 0;
}
public static implicit operator DomainTypeToBeHandldedAsInt(int s)
{
return new DomainTypeToBeHandldedAsInt { Value = s };
}
public int ToInt32(IFormatProvider provider)
{
return Value;
}
//All the rest throw a NotImplementedException
}
然后我将类型添加到RunTimeModel中:
var model = ProtoBuf.Meta.RuntimeTypeModel.Default;
model[typeof(TestClass)].Add(2, "DomainTypeToBeHandldedAsInt", typeof(Int32), null);
这导致了一个像这样的.proto文件:
syntax = "proto3";
package ProtoBufferSerializerTest;
message TestClass {
string StringProperty = 1;
repeated int32 DomainTypeToBeHandldedAsInt = 2 [packed = false];
}
但我不想重复这一点,我也不需要[packed = false]。
答案 0 :(得分:2)
这是一个非常有趣的问题。目前,答案是"不,不支持",但是:支持以下 ,如果您启用{ {1}}(在RuntimeTypeModel
实例上 - RuntimeTypeModel.Default
是Serializer.*
方法背后的实例):
public class DomainTypeToBeHandldedAsString
{
public string Value { get; set; }
public override string ToString() => Value;
public static DomainTypeToBeHandldedAsString Parse(string s)
=> new DomainTypeToBeHandldedAsString { Value = s };
}
基本上,它会查找public static {Type} Parse(string)
模式。但是:我同意明确表达这一点更好,而且#34;代理作为字符串"传达这个是一种很好的方式。我愿意为你在问题中的内容添加直接支持,但是现在还没有,需要进行一些代码更改。可能不是很多,因为该功能的 essentials 已经通过parseable-types存在!
这是一个可解析类型的方法,在一个应该在今天工作的例子中工作:
using ProtoBuf;
using ProtoBuf.Meta;
public class DomainTypeToBeHandldedAsString
{
public string Value { get; set; }
public override string ToString() => Value;
public static DomainTypeToBeHandldedAsString Parse(string s)
=> new DomainTypeToBeHandldedAsString { Value = s };
}
[ProtoContract]
public class Bar
{
[ProtoMember(1)]
public DomainTypeToBeHandldedAsString A { get; set; }
}
class Program
{
static void Main()
{
RuntimeTypeModel.Default.AllowParseableTypes = true;
var obj = new Bar { A = new DomainTypeToBeHandldedAsString { Value = "abcdef" } };
var clone = Serializer.DeepClone(obj);
System.Console.WriteLine(clone.A.Value);
}
}