简体   繁体   English

我无法使用XmlSerializer序列化C#中的对象列表

[英]I can't serialize a list of objects in C# with XmlSerializer

I have a list of many test implements the interface IDoTest, that I want to store in a file. 我有一个许多测试工具的列表,接口IDoTest,我想存储在一个文件中。 I also want to read from this file. 我也想从这个文件中读取。

It seemed natural to simple use the XmlSerializer to store the objects in my List of IDoTest. 简单地使用XmlSerializer将对象存储在我的IDoTest列表中似乎很自然。 But when I do this I get a vague I am sorry I cant do that error in the neighborhood of System.Xml.Serialization.TypeDesc.CheckSupported() 但是,当我这样做时,我得到一个模糊的我很抱歉我不能在System.Xml.Serialization.TypeDesc.CheckSupported()附近做错误

Can the XmlSerializer only do trivial jobs? XmlSerializer可以只做琐碎的工作吗? Or am I missing something? 或者我错过了什么? They are talking about custom serialization at MSDN. 他们正在谈论MSDN上的自定义序列化 Here is my simplified code example. 这是我的简化代码示例。

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

namespace ConsoleApplication1
{
    public interface IDoTest
    {
        void DoTest();
        void Setup();
    }
    internal class TestDBConnection : IDoTest
    {
        public string DBName;
        public void DoTest()
        {
            Console.WriteLine("DoHardComplicated Test");
        }
        public void Setup()
        {
            Console.WriteLine("SetUpDBTest");
        }
    }
    internal class PingTest : IDoTest
    {
        public string ServerName;
        public void DoTest()
        {
            Console.WriteLine("MaybeDoAPing");
        }
        public void Setup()
        {
            Console.WriteLine("SetupAPingTest");
        }
    }     

    internal class Program
    {
        private static void Main(string[] args)
        {

            TestDBConnection Do1 = new TestDBConnection { DBName = "SQLDB" };
            PingTest Do2 = new PingTest { ServerName = "AccTestServ_5" };
            List<IDoTest> allTest = new List<IDoTest> { Do1, (Do2) };
            // Now I want to serialize my list. 
            // Its here where I get the error at allTest
            XmlSerializer x = new XmlSerializer(allTest.GetType());
            StreamWriter writer = new StreamWriter("mySerializedTestSuite.xml");
            x.Serialize(writer, allTest); 

        }
    }
}

XmlSerializer cannot serialize an interface , and by extension, it cannot serialize a List<> of some interface. XmlSerializer无法序列化interface ,并且通过扩展,它无法序列化某个接口的List<> It can only serialize concrete object types. 它只能序列化具体的对象类型。

The assumption is that you will probably want to deserialize the objects at some point, and if it only output information pertaining to that interface, it can't guarantee that all the necessary data is present to reconstruct the original objects. 假设您可能希望在某个时刻反序列化对象,如果它只输出与该接口有关的信息,则无法保证存在所有必需的数据来重建原始对象。

This post shows a potential workaround, if you are able to use an abstract base class and explicitly provide every possible type of object that may appear in the list. 如果您能够使用抽象基类并明确提供可能出现在列表中的每种可能类型的对象,则此帖子显示了一种潜在的解决方法。

I followed the link that StriplingWarrior gave and found this excellent answer. 我按照StriplingWarrior给出的链接找到了这个优秀的答案。 https://stackoverflow.com/a/15089253/648076 from webturner 来自webturner的 https://stackoverflow.com/a/15089253/648076

I changed his implementation and made a class class ListOfToDo that implemented both List and IXmlSerializable. 我改变了他的实现,并创建了一个实现List和IXmlSerializable的类类ListOfToDo。 That worked! 那很有效! Here is my changed code. 这是我改变的代码。

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

namespace ConsoleApplication1
{
    public interface IDoTest
    {
        void DoTest();
        void Setup();
    }
    public class TestDBConnection : IDoTest
    {
        public string DBName;
        public void DoTest()
        {
            Console.WriteLine("DoHardComplicated Test");
        }
        public void Setup()
        {
            Console.WriteLine("SetUpDBTest");
        }
    }
    public class PingTest : IDoTest
    {
        public string ServerName;
        public void DoTest()
        {
            Console.WriteLine("MaybeDoAPing");
        }
        public void Setup()
        {
            Console.WriteLine("SetupAPingTest");
        }
    }

    public class ListOfToDo : List<IDoTest>, **IXmlSerializable**
    {    
        #region IXmlSerializable
        public XmlSchema GetSchema(){ return null; }

        public void ReadXml(XmlReader reader)

           {
               reader.ReadStartElement("ListOfToDo");
               while (reader.IsStartElement("IDoTest"))
            {
                Type type = Type.GetType(reader.GetAttribute("AssemblyQualifiedName"));
                XmlSerializer serial = new XmlSerializer(type);

                reader.ReadStartElement("IDoTest");
                this.Add((IDoTest)serial.Deserialize(reader));
                reader.ReadEndElement(); //IDoTest
            }
            reader.ReadEndElement(); //IDoTest
        }

        public void WriteXml(XmlWriter writer)
        {
            foreach (IDoTest test in this)
            {
                writer.WriteStartElement("IDoTest");
                writer.WriteAttributeString("AssemblyQualifiedName", test.GetType().AssemblyQualifiedName);
                XmlSerializer xmlSerializer = new XmlSerializer(test.GetType());
                xmlSerializer.Serialize(writer, test);
                writer.WriteEndElement();
            }
        }
         #endregion
    }

    internal class Program
    {
        private static void Main(string[] args)
        {

            TestDBConnection Do1 = new TestDBConnection { DBName = "SQLDB" };
            PingTest Do2 = new PingTest { ServerName = "AccTestServ_5" };
            ListOfToDo allTest = new ListOfToDo { Do1, (Do2) };

            // Now I want to serialize my list. 
            // Its here where I get the error at allTest
            XmlSerializer x = new XmlSerializer(allTest.GetType());
            StreamWriter writer = new StreamWriter("mySerializedTestSuite.xml");
            x.Serialize(writer, allTest); 
            writer.Flush();
            writer.Close();

            //Read it aka deserialize
            {
                var xmlSerializer = new XmlSerializer(typeof(ListOfToDo));
                var xmlReader = XmlReader.Create(new StreamReader("mySerializedTestSuite.xml"));
                ListOfToDo readWhatToTest = (ListOfToDo)xmlSerializer.Deserialize(xmlReader);
                xmlReader.Close();
            }


        }
    }
}

Output will then be: 输出将是:

    <?xml version="1.0" encoding="utf-8"?>
<ListOfToDo>
  <IDoTest AssemblyQualifiedName="ConsoleApplication1.TestDBConnection, ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
    <TestDBConnection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <DBName>SQLDB</DBName>
    </TestDBConnection>
  </IDoTest>
  <IDoTest AssemblyQualifiedName="ConsoleApplication1.PingTest, ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
    <PingTest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <ServerName>AccTestServ_5</ServerName>
    </PingTest>
  </IDoTest>
</ListOfToDo>

Not sure if this might be the cause of your issue but on these two examples they do use typeof(T) instead of T.GetType() 不确定这可能是您的问题的原因,但在这两个示例中,他们确实使用typeof(T)而不是T.GetType()

http://msdn.microsoft.com/en-us/library/71s92ee1.aspx http://msdn.microsoft.com/en-us/library/71s92ee1.aspx

I can't serialize a list of objects in C# with XmlSerializer 我无法使用XmlSerializer序列化C#中的对象列表

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM