ProtoInclude для полей?

У меня есть простой объект

[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, чтобы сказать «ожидайте эти типы», но, к сожалению, они являются атрибутом только класса. Кто-нибудь знает, как я могу обойти это? Для фона ключ открытого объекта здесь по историческим причинам (и повсюду), поэтому я очень хотел бы избежать матери всех рефакторингов ;-) Любой шанс, что я мог бы получить это для сериализации, даже заставить его сериализовать как строка ?


person Big    schedule 24.09.2009    source источник


Ответы (1)


Есть действительно несколько приемов, которые могут сработать; string, который вы упомянули, довольно прост (с использованием частного свойства, отмеченного [ProtoMember]), но я не уверен, как вы узнаете, в какой тип его преобразовать.

Однако существует основанный на наследовании ([ProtoInclude]) способ обработки конечного числа типов (известного заранее). Вот связанный пример< /a>, но я посмотрю, смогу ли я сделать это более конкретным для этого случая...


Что касается подходов на основе строк, вы могли бы использовать префикс? то есть что-то вроде:

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; }
}
person Marc Gravell    schedule 24.09.2009