2017-07-26 20 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意味着什麼。 –