Наследование здесь не является проблемой, так как даже если A : B
, то Foo<A> : Foo<B>
неверно. Обратите внимание, что protobuf-net не будет использовать конструктор не по умолчанию, хотя возможно пропустить конструктор, привязав его непосредственно к полю (даже readonly
). Хотя у вас может быть 6 T
, я не вижу (из кода), что когда-либо возникнут сомнения в том, какой закрытый тип вы намереваетесь, и если закрытый тип известен, вам следует установить.
Если у вас есть Foo<SomeBaseClass>
и несколько конкретных типов, унаследованных от SomeBaseClass
, то маркеры будут на SomeBaseClass
.
Однако, если у вас есть конкретный сценарий, который я могу использовать для воспроизведения вашей проблемы, я с удовольствием посмотрю.
Обновлена повторная редакция:
В примере выделено несколько ключевых моментов:
- Как и большинство API связывания, XmlSerializer и IIRC DataContractSerializer, элемент представляет собой либо список xor элемент со значениями ; если коллекция (что-то реализующее
IList
) сама имеет свойства, они не будут сериализованы; инкапсуляция здесь предпочтительнее наследования, то есть то, что имеет a Name
, а имеет список (а не имеет a Name
и - это список)
- protobuf-net v1 не поддерживает сериализацию на основе интерфейса; v2 делает , но, как и в случае с XmlSerializer и DataContractSerializer, вам нужно явно указать ему, чего ожидать; довольно мило, однако, мы можем переместить
[ProtoMember]
на сам интерфейс
Вот полностью рабочая версия в v2:
using System.Collections.Generic;
using ProtoBuf;
[ProtoContract]
class MySpecialCollectionList<T>
{
[ProtoMember(1)]
public string Name { get; set; }
private readonly List<MySpecialCollection<T>> items = new List<MySpecialCollection<T>>();
[ProtoMember(2)]
public List<MySpecialCollection<T>> Items { get { return items; } }
}
[ProtoContract]
class MySpecialCollection<T>
{
[ProtoMember(1)]
public string Name { get; set; }
private readonly List<Special<T>> items = new List<Special<T>>();
[ProtoMember(2)]
public List<Special<T>> Items { get { return items; } }
}
[ProtoContract]
class Special<T>
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public string Description { get; set; }
[ProtoMember(3)]
private readonly T _source;
T Source { get { return _source; } }
private Special()
{
}
public Special(T source)
{
_source = source;
}
}
[ProtoContract]
[ProtoInclude(2, typeof(Ant))]
[ProtoInclude(3, typeof(Cat))]
[ProtoInclude(4, typeof(Dog))]
interface IBeast
{
[ProtoMember(1)]
string Name { get; set; }
}
[ProtoContract]
class Ant : IBeast
{
public string Name { get; set; }
}
[ProtoContract]
class Cat : IBeast
{
public string Name { get; set; }
}
[ProtoContract]
class Dog : IBeast
{
public string Name { get; set; }
}
public static class Form1
{
private static void Main()
{
MySpecialCollectionList<IBeast> collectionList = GetSpecialCollectionList();
var copy = Serializer.DeepClone(collectionList);
}
private static MySpecialCollectionList<IBeast> GetSpecialCollectionList()
{
var ant = new Ant() { Name = "Mr Ant" };
var cat = new Cat() { Name = "Mr Cat" };
var dog = new Dog() { Name = "Mr Dog" };
var Special = new Special<IBeast>(ant);
var specialCollection1 = new MySpecialCollection<IBeast>() {Items =
{new Special<IBeast>(ant),
new Special<IBeast>(cat),
new Special<IBeast>(dog)}
};
specialCollection1.Name = "Special Collection1";
var specialCollection2 = new MySpecialCollection<IBeast>()
{
Items =
{new Special<IBeast>(ant),
new Special<IBeast>(dog)}
};
specialCollection2.Name = "Special Collection2";
var specialCollectionList = new MySpecialCollectionList<IBeast>()
{
Items ={
specialCollection1, specialCollection2 }
};
specialCollectionList.Name = "Special Collection List";
return specialCollectionList;
}
}