2017-07-26 33 views
2

我想序列化为protobuf格式的C#类,它具有特定于域的特性类型。但是这些类型应该作为值类型来处理。protobuf-net使用字符串类型作为代理

我正在使用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]; 
} 

但我不希望这是重复的,我不需要[包装=假]无论是。

回答

2

这是一个非常有趣的问题。目前,答案是“不,不支持”,但是:以下支持,如果启用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); 
    } 
} 
+0

感谢马克......我发现AllowParseableTypes选择自己,但因为我也想支持INT,小数等。并没有解决我所有的问题。将一个代理项定义为一个字符串也是比较清晰的,因为我不必在我的DomainTypeToBeHandldedAsString中引入两个新方法。 –

+0

我目前没有太多的空闲时间,但是在不太可能的情况下,我找到了一些,然后你可以指向我的代码中的哪个位置,我将不得不执行此操作?然后,我会高兴地写一个拉请求。我现在的时间非常有限,所以不要等我,但如果可以的话,我会尽力帮忙。 –

+0

我几乎按照自己的意愿工作。而不是设置一个替代品,我在** DomainTypeToBeHandldedAsInt **上实现了IConvertible,并添加了如下属性:** model [typeof(TestClass)]。Add(1,“DomainTypeToBeHandldedAsInt”,typeof(Int32),null); **但是产生了这样的结果:**重复int32 DomainTypeToBeHandldedAsInt = 1 [packed = false]; **不完全是我正在寻找,但接近。该类型实际上没有重复,我不知道什么packed = false意味着什么。 –

相关问题