【问题标题】:Serializing interfaces序列化接口
【发布时间】:2011-01-11 15:27:10
【问题描述】:

我正在尝试运行类似这样的代码:

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 不应该解决这个问题吗?

【问题讨论】:

  • 谁说过反序列化...?

标签: c# xml-serialization


【解决方案1】:

没有。您不能序列化接口。曾经。它只是告诉你。

接口只不过是对一组行为的描述。它没有说明实例的内容。特别是,虽然实现接口的类的实例必须实现其所有成员,但它肯定会有自己的属性需要序列化。

如何反序列化?

将使用什么类来反序列化另一端的接口?

【讨论】:

  • @Shahar:是的。不要这样做。使用具体类型,而不是接口。
  • 如何反序列化?作为被序列化的类的实例,与 List 相同。什么类将用于反序列化另一端的接口?查看第一个答案。
  • @John Saunder 我强烈反对你的说法。以接口 IShape 和 Rectangle 的经典案例为例,Circle 实现了它,MyObject 引用了 IShape。现在,如果我需要 MyObject 可序列化怎么办? “不要这样做”简单没有任何意义,因为我的类结构必须遵循一些通用设计原则,这也涉及使用接口。我不想仅仅因为我不能序列化接口和“不要那样做”之类的声明而没有糟糕的设计,因为序列化排在好设计之后,IMO。
  • @JohnSaunders,当您说“您做不到”时,您的第一段是正确的。你所说的其他一切都试图证明为什么会这样。这些理由都​​是假的。取一个接口,并用一个没有成员的抽象类替换它。这根本不会改变代码的工作方式。一下子就可以序列化了!
  • 另外,您在上面的评论中确实说过“不要那样做”。
【解决方案2】:

这是我原则上倾向于使用的未经测试的阴暗解决方法:

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&lt;Class2&gt;。请记住提供接口可能假定的任何类型。


我看不出任何序列化程序不能序列化这些属性的原因。这不像你真的尝试序列化一个接口,你尝试序列化一个实现某个接口的对象(这与抽象子类化并没有太大区别,一些编程语言甚至只对接口进行操作)。

当序列化程序应该序列化该对象时它知道该对象实现了该接口,它真正要做的就是序列化它并附加类型属性(就像序列化抽象类或只是一般的超类)。

现在反序列化器查看类型,可以检查该对象是否确实实现了所需的接口,然后将其反序列化为相应的属性。

【讨论】:

  • 阿门。序列化器在这方面是愚蠢的!感谢您的解决方法。使用接口要好得多,因为继承仅限于一个基类。
【解决方案3】:

或者改用DataContractSerializer

【讨论】:

【解决方案4】:

你包含了 typeof(List<...>),但 MyArray 是 IList<...> 类型,它本身并没有明显的数据结构,而是更多的占位符来获取一些数据结构。

将 MyArray 的类型更改为特定类型(例如 List),它应该可以工作。

    private List<Class2> myArray;

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-05
    • 2011-12-25
    • 2012-02-27
    • 1970-01-01
    相关资源
    最近更新 更多