2009-09-24 106 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; } 
}