Сериализация интерфейсов - PullRequest
10 голосов
/ 11 января 2011

Я пытаюсь запустить код, подобный этому:

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;

namespace ConsoleApplication1
{
    [Serializable]
    [XmlInclude(typeof(List<Class2>))]
    public class Class1
    {
        private IList<Class2> myArray;

        public IList<Class2> MyArray
        {
            get { return myArray; }
            set { myArray = value; }
        }

    }

    public class Class2
    {
        private int myVar;

        public int MyProperty
        {
            get { return myVar; }
            set { myVar = value; }
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            XmlSerializer ser = new XmlSerializer(typeof(Class1), new Type[] { typeof(List<Class2>) });
            FileStream stream = File.OpenWrite("Data.xml");
            ser.Serialize(stream, new List<Class1>());
            stream.Close();
        }
    }
}

Может кто-нибудь объяснить мне, что я делаю не так?

Я получаю:

Невозможно сериализовать элемент .. MyArray ..., поскольку это интерфейс.

Разве XmlInclude не может решить эту проблему?

Ответы [ 4 ]

14 голосов
/ 11 января 2011

Нет. Вы не можете сериализовать интерфейс. Когда-либо. Это только что сказал тебе.

Интерфейс - это не что иное, как описание набора поведений. Это ничего не говорит о содержании экземпляра. В частности, хотя экземпляр класса, реализующего интерфейс, должен реализовывать все его члены, он, безусловно, будет иметь собственные свойства, которые необходимо сериализовать.

Как бы это было десериализовано?

Какой класс будет использоваться для десериализации интерфейса на другой стороне?

13 голосов
/ 10 февраля 2011

Вот непроверенный теневой обходной путь, который я склонен использовать в принципе:

private IList<Class2> myArray;
[XmlIgnore]
public IList<Class2> MyArray
{
    get { return myArray; }
    set { myArray = value; }
}

[XmlElement("MyArray")]
public object MyArraySerializable
{
    get { return MyArray; }
    set { MyArray = value as IList<Class2>; }
}

Это будет сериализовать любой список, который вы можете использовать, как общий объект с атрибутом типа, который сообщит десериализатору фактический типобъект, поэтому, когда этот объект десериализован, он должен быть снова приведен к IList<Class2>.Не забудьте предоставить любые типы, которые могут быть приняты интерфейсом.


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

Когдасериализатор должен сериализовать этот объект он знает , что объект реализует этот интерфейс, все, что ему действительно нужно, это сериализовать его и присоединить атрибут типа (как это происходит, если вы сериализуете абстрактные классы или просто суперклассы вgeneral).

Теперь десериализатор просматривает тип и может проверить , действительно ли этот объект реализует требуемый интерфейс, а затем десериализовать его в соответствующее свойство.

9 голосов
/ 15 июля 2011

Или используйте взамен DataContractSerializer .

0 голосов
/ 11 января 2011

Вы включили typeof (List <...>), но MyArray имеет тип IList <...>, который сам по себе не является очевидной структурой данных, а скорее заполнителем для некоторой структуры данных.

Измените тип MyArray на определенный тип (например, List, например), и он должен работать.

    private List<Class2> myArray;

    public List<Class2> MyArray
    {
        get { return myArray; }
        set { myArray = value; }
    }
...