Использование DataContractSerializer с общими известными типами, которые имеют интерфейсы в качестве параметров типа - PullRequest
0 голосов
/ 05 ноября 2018

Я сериализую универсальные типы с DataContractSerializer. Он прекрасно работал до тех пор, пока класс не имел двух известных типов, которые являются двумя версиями универсального типа с различными интерфейсами в качестве универсального параметра.

Вот самый простой пример, который я мог бы быстро собрать. Существует два интерфейса (IInterfaceA и IInterfaceB), реализованные некоторыми типами (ImplementationA и ImplementationB). Существует универсальный тип Generic<T>, который реализует некоторый другой интерфейс IOtherInterface. И есть класс, который я хочу сериализовать, HereComesTrouble, который содержит два члена данных этого интерфейса.

Я использовал атрибуты KnownType для перечисления всех возможных конкретных типов, которые могут встречаться в графе сериализованных объектов. Generic<ImplementationA> и Generic<ImplementationB> перечислены , а не , поскольку эти типы никогда не будут существовать.

Это сообщение InvalidOperationException, которое я получаю при запуске кода:

Тип 'Test.Generic`1 [Test.IInterfaceB]' нельзя добавить в список известные типы, начиная с другого типа 'Test.Generic`1 [Test.IInterfaceA]' с то же имя контракта данных http://schemas.datacontract.org/2004/07/Test:GenericOfanyType' уже присутствует. Если есть разные коллекции конкретного type - например, List и Test [], они не могут быть оба добавлены как известные типы. Попробуйте указать только один из этих типов для дополнение к списку известных типов.

Как мне обойти эту проблему?

using System.IO;
using System.Runtime.Serialization;

namespace Test
{
    internal interface IInterfaceA { }
    internal interface IInterfaceB { }

    [DataContract]
    internal class ImplementationA : IInterfaceA { }
    [DataContract]
    internal class ImplementationB : IInterfaceB { }

    internal interface IOtherInterface { }

    [DataContract]
    internal class Generic<T> : IOtherInterface
    {
        [DataMember]
        public T GenericData { get; set; }
    }

    [DataContract]
    [KnownType(typeof(ImplementationA))]
    [KnownType(typeof(ImplementationB))]
    [KnownType(typeof(Generic<IInterfaceA>))]
    [KnownType(typeof(Generic<IInterfaceB>))] // <-- Removing this one line makes everything work.
    internal class HereComesTrouble
    {
        [DataMember]
        public IOtherInterface Member1 { get; set; }
        [DataMember]
        public IOtherInterface Member2 { get; set; }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            var toSerialize = new HereComesTrouble();

            var serializer = new DataContractSerializer(typeof(HereComesTrouble));
            using (var memoryWriter = new MemoryStream())
                serializer.WriteObject(memoryWriter, toSerialize); // <-- InvalidOperationException!
        }
    }
}
...