我正在尝试将一个 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));
但这失败了,出现了这个异常(exception):
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]。
最佳答案
这是一个非常有趣的问题。目前,答案是“不,不支持”,但是:支持以下,如果您启用AllowParseableTypes
(在 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)
模式。但是:我同意明确表达这一点会更好,“代理项作为字符串”是表达这一点的好方法。我愿意为您在问题中所拥有的内容添加直接支持,但今天不存在,需要进行一些代码更改。可能不是很多,因为该功能的要素已经通过可解析类型存在!
下面是在今天应该有效的示例中使用的可解析类型方法:
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);
}
}
关于c# - protobuf-net 使用字符串类型作为代理项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45323448/