Сериализация наследуемых классов с использованием protobuf-Net - PullRequest
2 голосов
/ 02 марта 2012

У меня проблема с сериализацией производных классов с использованием protobuf-net. Я не знаю, так ли это, потому что это не поддерживается, или я делаю что-то не так.

У меня есть базовый базовый класс (который я могу сериализовать напрямую), и затем я делаю специализацию этого, но этот я не могу сериализовать. Ниже приведен код для двух классов и пример использования. Я делаю что-то не так?

Редактировать

Добавлено ограничение для универсальных типов

База

[ProtoBuf.ProtoContract]
public class Base<TKey, TValue>
    where TKey : Key
    where TValue : Key
{
    [ProtoBuf.ProtoMember(1)]
    public Dictionary<TKey, Dictionary<TKey, TValue>> Data { get; set; }
    [ProtoBuf.ProtoMember(2)]
    public TValue DefaultValue { get; set; }

    public Base()
    {
        this.Data = new Dictionary<TKey, Dictionary<TKey, TValue>>();
    }

    public Base(TValue defaultValue)
        : this()
    {
        this.DefaultValue = defaultValue;
    }

    public TValue this[TKey x, TKey y]
    {
        get
        {
            try { return this.Data[x][y]; }
            catch { return this.DefaultValue; }
        }
        set
        {
            if (!this.Data.ContainsKey(x))
                this.Data.Add(x, new Dictionary<TKey, TValue> { { y, value } });
            else
                this.Data[x][y] = value;
        }
    }
}

Ключевой класс

public abstract class Key
{
}

Специализированный ключ

[ProtoBuf.ProtoContract]
public class IntKey : Key
{
    [ProtoBuf.ProtoMember(1)]
    public int Value { get; set; }

    public IntKey() { }

    public override int GetHashCode()
    {
        return this.Value.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(obj, null)) return false;
        if (ReferenceEquals(obj, this)) return true;

        var s = obj as IntKey;
        return this.Value.Equals(s.Value);
    }
}

Специализированный класс

[ProtoBuf.ProtoContract]
public class IntWrapper<TKey> : Base<TKey, IntKey>
    where TKey : Key
{
    public IntWrapper()
        : base() { }

    public IntWrapper(IntKey defaultValue)
        : base(defaultValue) { }
}

Пример использования

var path = @"C:\Temp\data.dat";
var data = new IntWrapper<IntKey>(new IntKey { Value = 0 }); // This will not be serialized
for(var x = 0; x < 10; x++)
{
    for(var y = 0; y < 10; y++)
        data[new IntKey { Value = x }, new IntKey { Value = y }] = new IntKey { Value = x + y };
}

using (var fileStream = new FileStream(path, FileMode.Create))
{
    ProtoBuf.Serializer.Serialize(fileStream, data);
}

1 Ответ

2 голосов
/ 02 марта 2012

Модель должна понимать в терминах прототипа взаимосвязь между базовым типом и подтипом, в частности поле, используемое для его уникальной идентификации. Обычно это делается с помощью атрибутов базового типа, но это проблематично при использовании шаблонов, поскольку вы не можете использовать typeof(SomeType<TKey>) в атрибуте. Вы можете определить это во время выполнения, хотя:

RuntimeTypeModel.Default.Add(typeof (Base<int,int>), true)
              .AddSubType(3, typeof (IntWrapper<int>));

После этого все работает.

...