带有System.Object对象的XmlSerializer

时间:2012-05-08 09:26:06

标签: c# .net serialization exception-handling xmlserializer

我似乎无法找到对此的明确回应,这让我发疯。 XmlSerializer类似乎适用于任何已定义的内容,甚至适用于嵌套类。但是当其中一个类包含System.Object时,它就会呕吐。有没有人知道一个简单的方法呢?

namespace test
{
    public class SomeList
    {
        public object obj;
    }

    public class Person
    {
        public string first;
        public string last;
    }

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("Creating object...");
                Person me = new Person();
                me.first = "MyFirst";
                me.last = "MyLast";

                Console.WriteLine("- Serialized: " + serialize_xml<Person>(me));
                Console.WriteLine("");
                Console.WriteLine("Creating object with embedded generic...");
                SomeList test = new SomeList();
                test.obj = me;
                Console.WriteLine("- Serialized: " + serialize_xml<SomeList>(test));

                Console.WriteLine("");
                Console.Write("Press ENTER to exit.");
                Console.ReadLine();
                return;
            }
            catch (Exception e)
            {
                print_exception(e);
                Console.WriteLine("");
                Console.Write("Press ENTER to exit.");
                Console.ReadLine();
                return;
            }
        }

        static string serialize_xml<T>(T obj)
        {
            XmlSerializer xmls = new XmlSerializer(typeof(T));
            using (MemoryStream ms = new MemoryStream())
            {
                XmlWriterSettings settings = new XmlWriterSettings();
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("", "");

                settings.Encoding = Encoding.UTF8;
                settings.Indent = false;
                settings.NewLineChars = "";
                settings.NewLineHandling = NewLineHandling.None;
                settings.NewLineOnAttributes = false;
                settings.ConformanceLevel = ConformanceLevel.Document;
                settings.OmitXmlDeclaration = true;

                using (XmlWriter writer = XmlTextWriter.Create(ms, settings))
                {
                    xmls.Serialize(writer, obj, ns);
                }

                string xml = Encoding.UTF8.GetString(ms.ToArray());

                // remove the BOM character at the beginning which screws up decoding
                if (xml.Length > 0 && xml[0] != '<')
                {
                    xml = xml.Substring(1, xml.Length - 1);
                }
                return xml;
            }
        }

        static void print_exception(Exception e)
        {
            Console.WriteLine(" = Exception Type: " + e.GetType().ToString());
            Console.WriteLine(" = Exception Dat " + e.Data);
            Console.WriteLine(" = Inner Exception: " + e.InnerException);
            Console.WriteLine(" = Exception Message: " + e.Message);
            Console.WriteLine(" = Exception Source: " + e.Source);
            Console.WriteLine(" = Exception StackTrace: " + e.StackTrace);
        }
    }
}

在控制台上创建以下输出:

 = Exception Type: System.InvalidOperationException
 = Exception Dat System.Collections.ListDictionaryInternal
 = Inner Exception: System.InvalidOperationException: The type test.Person was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
   at System.Xml.Serialization.XmlSerializationWriter.WriteTypedPrimitive(String name, String ns, Object o, Boolean xsiType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterSomeList.Write1_Object(String n, String ns, Object o, Boolean isNullable, Boolean needType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterSomeList.Write2_SomeList(String n, String ns,SomeList o, Boolean isNullable, Boolean needType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterSomeList.Write3_SomeList(Object o)
 = Exception Message: There was an error generating the XML document.
 = Exception Source: System.Xml
 = Exception StackTrace:    at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces)
   at test.Program.serialize_xml[T](T obj) in C:\Users\jchristn\Documents\Visual Studio 2010\Projects\test\test\Program.cs:line 83
   at test.Program.Main(String[] args) in C:\Users\jchristn\Documents\Visual Studio 2010\Projects\test\test\Program.cs:line 47

1 个答案:

答案 0 :(得分:5)

假设有一组固定的对象SomeList.obj可以包含,并且该集在编译时是已知的, 您可以使用XmlIncludeAttribute

在容器类上指定它们
[XmlInclude(typeof(Person))]
[XmlInclude(typeof(Other))]
public class SomeList
{
    public object obj;
}

public class Person
{
    public string first;
    public string last;
}

public class Other
{
    public int MyProperty { get; set; }
}

如果在编译时未知类型,则可以在XmlSerializer构造函数的重载中指定类型数组:

XmlSerializer xmls = new XmlSerializer(typeof(T), new Type[] { <...types...> });