确实有一些技巧可能会奏效;您提到的那个string
非常简单(通过使用标有 的私有属性[ProtoMember]
),但我不确定您如何知道将其转换回的类型。
但是,有一种基于继承的 ( [ProtoInclude]
) 方法来处理有限数量的类型(预先知道)。这是一个相关的例子,但我会看到我可以让它更具体地适用于这种情况......
关于基于字符串的方法,您可以使用前缀吗?即类似的东西:
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
}
}
好的; 这是一个例子;我强调使用固定键会更好。以下有点难看,但大部分代码都可以隐藏起来并重新使用,所以可能还不错。不过,我更喜欢强类型的键。我可能已经提到过;-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; }
}