2012-03-02 2 views
2

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

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

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

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

Base

[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; 
     } 
    } 
} 

Key класс

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); 
} 

ответ

2

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

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

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

+0

Хорошо, что, если я ограничу сферу родового типа наследованием от определенного абстрактного класса (я добавил это в Q). Итак, теперь базовая структура допускает типы, которые имеют тип 'Key', облегчит ли это? – aweis

+0

@aweis нужно будет увидеть конкретный пример; но: большинство ** обычных ** сценариев можно обрабатывать с помощью '[ProtoInclude (...)]' –

+0

Пример в значительной степени является кодом в вопросе. Моя самая большая проблема заключается в том, что я не могу контролировать, какие типы даются базовому классу, но я могу потребовать, чтобы они были сериализуемыми, поэтому я думал, что ограничение их наследования определенного базового класса также ограничило бы сферу применения! – aweis