2009-09-24 108 views
0

我有一個簡單的對象Proto包括字段?

[ProtoContract] 
public class DataChangedEventArgs<T> : EventArgs 
{ 
    private readonly object key; 
    private readonly T data; 
    private readonly DataChangeType changeType; 

    ///<summary> 
    /// Key to identify the data item 
    ///</summary> 
    public object Key 
    { 
     get { return key; } 
    } 

    [ProtoMember(2, IsRequired = true)] 
    public T Data 
    { 
     get { return data; } 
    } 

    [ProtoMember(3, IsRequired = true)] 
    public DataChangeType ChangeType 
    { 
     get { return changeType; } 
    } 

和我有一個關鍵的問題。它的類型是對象,但它可以是int,long或string。 我會直觀地使用ProtoInclude屬性來說「期待這些類型」,但不幸的是,它們只是類的屬性。 有沒有人有任何想法我可以解決這個問題? 對於背景來說,公鑰對象出於歷史原因(和所有地方),所以我非常想避免所有重構的母親;-) 任何機會,我可以得到這個序列化,甚至強迫它序列化爲一個字符串?

回答

2

確實有一些技巧可行;您提到的string很簡單(通過使用標有[ProtoMember]的私有財產),但我不知道如何知道將其轉換回的類型。

但是,有一種基於繼承([ProtoInclude])的方式來處理有限的數量的類型(事先已知)。這裏有一個related example,但我會看看我能說得具體些這種情況...


對於基於字符串的方法,你可以使用一個前綴?即是這樣的:

public object Key {get;set;} 

[ProtoMember(1)] 
private object KeyString { 
    get { 
     if(Key == null) return null; 
     if(Key is string) return "s:"+(string)Key; 
     if(Key is int) return "i:"+Key.ToString(); 
     // etc 
    } 
    set { 
     if(value == null) { Key = null; } 
     else if(value.StartsWith("s:")) {...} 
     // etc 
    } 
} 

OK;這裏是一個例子;我強調這將是好得多使用固定鍵;以下是有點難看,但大部分代碼可以隱藏並重新使用,所以也許不是不好。不過,我更喜歡更強大的鍵。我可能已經提到過了;-p

using System; 
using ProtoBuf; 
static class Program 
{ 
    static void Main() 
    { 
     var message1 = new SomeMessageWithVariableKey<string>(123456, "abcdef"); 
     var clone1 = Serializer.DeepClone(message1); 
     Console.WriteLine(clone1.Key); 
     Console.WriteLine(clone1.SomeOtherValue); 

     var message2 = new SomeMessageWithVariableKey<int>("abcdef", 123456); 
     var clone2 = Serializer.DeepClone(message2); 
     Console.WriteLine(clone2.Key); 
     Console.WriteLine(clone2.SomeOtherValue); 
    } 
} 

[ProtoContract] 
[ProtoInclude(1, typeof(ProtoKey<int>))] 
[ProtoInclude(2, typeof(ProtoKey<string>))] 
abstract class ProtoKey 
{ 
    public static ProtoKey Create(object key) 
    { 
     if (key == null) return null; 
     if (key is string) return new ProtoKey<string> { Value = key }; 
     if (key is int) return new ProtoKey<int> { Value = key }; 
     throw new ArgumentException("Unexpected key type: " + key.GetType().Name); 
    } 

    public abstract object Value { get; protected set;} 
    public override string ToString() 
    { 
     return Convert.ToString(Value); 
    } 
    public override bool Equals(object obj) 
    { 
     ProtoKey other = obj as ProtoKey; 
     if (other == null) return false; 
     return object.Equals(Value, other.Value); 
    } 
    public override int GetHashCode() 
    { 
     object val = Value; 
     return val == null ? 0 : val.GetHashCode(); 
    } 
} 
[ProtoContract] 
sealed class ProtoKey<T> : ProtoKey 
{ 
    [ProtoMember(1)] 
    public T TypedValue { get; set; } 
    public override object Value 
    { 
     get { return TypedValue; } 
     protected set { TypedValue = (T)value; } 
    } 
} 

[ProtoContract] 
public class SomeMessageWithVariableKey<T> 
{ 
    private SomeMessageWithVariableKey() { } 
    public SomeMessageWithVariableKey(object key, T someOtherValue) { 
     Key = key; 
     SomeOtherValue = someOtherValue; 
    } 
    public object Key { get; private set; } 

    [ProtoMember(1)] 
    private ProtoKey SerializationKey 
    { 
     get { return ProtoKey.Create(Key); } 
     set { Key = value == null ? null : value.Value; } 
    } 
    [ProtoMember(2)] 
    public T SomeOtherValue { get; set; } 
}