使用 DataContract 的问题 Xml 序列化 - KnownTypes

Problem to use DataContract Xml Serialization - KnownTypes

当我想 Xml 使用 DataContract 序列化时遇到问题,我有一个错误异常要求我使用 DataContractResolver 或添加未知类型...

我有 3 个可以使用 Dll 动态加载的插件:Class1、Class2 和 ClassPanel 以及一个插件属性 Class3,它对所有插件都是通用的。

我创建了不同的插件实例并将它们存储在容器中。 主 window 和面板有容器

所以我会序列化包含在容器、子容器和子容器中的每个插件...以及每个 属性 布局(Class3)。

所以我不知道添加 DataContract 所需的不同类型(动态)。也许在这种情况下无法使用 DataContract 而我这样做并编写了一个自定义程序来序列化?感谢您的帮助

//MainWindow.xaml.cs
using System.Runtime.Serialization;
using System.Windows;
using System.Xml;

namespace ClassApp1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var p = new Plugins();
            var type = p.GetType();
            var dcs = new DataContractSerializer(type);
            using (XmlWriter wr = XmlWriter.Create(@"j:\message.xml"))
            {
                dcs.WriteObject(wr, p);
            }
        }
    }
}

//Plugin.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;

namespace ClassApp1
{
    [DataContract]
    public class Plugins
    {
        [DataMember] public List<object> container = new List<object>();
        public List<Type> pluginTypes;
        public List<Assembly> assemblies = new List<Assembly>();

        public Plugins()
        {
            assemblies.Add(Assembly.LoadFile(System.IO.Path.Combine(@"J:\ProjetC#\Cockpit-master\ClassApp1\bin\Debug", "ClassLibrary3.dll")));
            assemblies.Add(Assembly.LoadFile(System.IO.Path.Combine(@"J:\ProjetC#\Cockpit-master\ClassApp1\bin\Debug", "ClassLibrary1.dll")));
            assemblies.Add(Assembly.LoadFile(System.IO.Path.Combine(@"J:\ProjetC#\Cockpit-master\ClassApp1\bin\Debug", "ClassLibrary2.dll")));
            assemblies.Add(Assembly.LoadFile(System.IO.Path.Combine(@"J:\ProjetC#\Cockpit-master\ClassPanel\bin\Debug", "ClassPanel.dll")));

            pluginTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(a => a.ToString().StartsWith("Class")).ToList();

            var listoftypes = new List<string> { "ClassLibrary1.Class1", "ClassLibrary2.Class2", "ClassPanel.ClassPanel" };
            var listofargs = new List<object> { new object[] { 1, "iamClass1" }, new object[] { 2, 123d }, new object[] { this } };

            for (int i = 0; i < listoftypes.Count(); i++)
            {
                container.Add(Activator.CreateInstance(GetType(listoftypes[i]), listofargs[i]));
            }
        }
        public Type GetType(string model)
        {
            foreach (var p in assemblies)
            {
                Type type = p.GetType(model);
                if (type != null)
                    return type;
            }
            return null;
        }
    }
}

//Class1.cs
using ClassLibrary3;
using System.Runtime.Serialization;

namespace ClassLibrary1
{
    [DataContract]
    public class Class1
    {
        [DataMember] public int id { get; set; }
        [DataMember] public string message { get; set; }
        [DataMember]public Class3 Layout { get; set; }

        public Class1(params object[] obj)
        {
            this.id = (int)obj[0];
            this.message =(string)obj[1];
            Layout = new Class3(id, "fromClass1");
        }
    }
}

//Class2.cs
using ClassLibrary3;
using System.Runtime.Serialization;

namespace ClassLibrary2
{
    [DataContract]
    public class Class2
    {
        [DataMember] public int id { get; set; }
        [DataMember] public double number { get; set; }
        [DataMember] public Class3 Layout { get; set; }

        public Class2(params object[] obj)
        {
            this.id = (int)obj[0];
            this.number = (double)obj[1];
            Layout = new Class3(id, "fromClass2");
        }
    }
}

//Class3.cs
using System.Runtime.Serialization;
using System.Windows.Forms;

namespace ClassLibrary3
{
    [DataContract]
    public class Class3
    {
        public Class3(int id, string name)
        {
            this.id = id;
            this.name = name;
            abc = "ABCDEF";
        }

       [DataMember] public int id { get; set; }
       [DataMember] public string name { get; set; }
       [DataMember] public string abc { get; set; }
    }
}

//ClassPanel.cs
using ClassApp1;
using ClassLibrary3;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

namespace ClassPanel
{
    [DataContract]
    public class ClassPanel
    {
        [DataMember]public List<object> container = new List<object>();

        [DataMember]public Class3 Layout { get; set; }

        public Plugins plg { get; set; }

        public ClassPanel(params object[] obj)
        {
            plg = (Plugins)obj[0];
            Layout = new Class3(0, "fromPanel");

            var listoftypes = new List<string> { "ClassLibrary1.Class1", "ClassLibrary2.Class2", "ClassLibrary1.Class1" };
            var listofargs = new List<object> { new object[] { 11, "iamClass1Panel" }, new object[] { 12, 11d }, new object[] { 12, "iamClass1BisPanel" } };

            for (int i = 0; i < listoftypes.Count(); i++)
            {
                container.Add(Activator.CreateInstance(plg.GetType(listoftypes[i]), listofargs[i]));
            }
        }
    }
}

好的,经过大量测试,我找到了一个解决方案 post 它可以帮助人们搜索: 解决方案是在一个数组中指明序列化所需的所有类型,作为 DataContractSerializer

的第二个参数
namespace ClassApp1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            var p = new Plugins();

            var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(a => a.ToString().StartsWith("ClassP") || a.ToString().StartsWith("ClassL")).ToArray();

            var type = p.GetType();
            var dcs = new DataContractSerializer(type, types);

            var settings = new XmlWriterSettings()
            {
                Indent = true,
                IndentChars = "    "
            };

            using (XmlWriter wr = XmlWriter.Create(@"j:\message.xml", settings))
            {
                dcs.WriteObject(wr,  p);
            }

        }
    }
}

设置XmlWriter的结果(缩进)

<?xml version="1.0" encoding="utf-8"?>
<Plugins xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ClassApp1">
    <container xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
        <d2p1:anyType xmlns:d3p1="http://schemas.datacontract.org/2004/07/ClassLibrary1" i:type="d3p1:Class1">
            <d3p1:Layout xmlns:d4p1="http://schemas.datacontract.org/2004/07/ClassLibrary3">
                <d4p1:abc>ABCDEF</d4p1:abc>
                <d4p1:id>1</d4p1:id>
                <d4p1:name>fromClass1</d4p1:name>
            </d3p1:Layout>
            <d3p1:id>1</d3p1:id>
            <d3p1:message>iamClass1</d3p1:message>
        </d2p1:anyType>
        <d2p1:anyType xmlns:d3p1="http://schemas.datacontract.org/2004/07/ClassLibrary2" i:type="d3p1:Class2">
            <d3p1:Layout xmlns:d4p1="http://schemas.datacontract.org/2004/07/ClassLibrary3">
                <d4p1:abc>ABCDEF</d4p1:abc>
                <d4p1:id>2</d4p1:id>
                <d4p1:name>fromClass2</d4p1:name>
            </d3p1:Layout>
            <d3p1:id>2</d3p1:id>
            <d3p1:number>123</d3p1:number>
        </d2p1:anyType>
        <d2p1:anyType xmlns:d3p1="http://schemas.datacontract.org/2004/07/ClassPanel" i:type="d3p1:ClassPanel">
            <d3p1:Layout xmlns:d4p1="http://schemas.datacontract.org/2004/07/ClassLibrary3">
                <d4p1:abc>ABCDEF</d4p1:abc>
                <d4p1:id>0</d4p1:id>
                <d4p1:name>fromPanel</d4p1:name>
            </d3p1:Layout>
            <d3p1:container>
                <d2p1:anyType xmlns:d5p1="http://schemas.datacontract.org/2004/07/ClassLibrary1" i:type="d5p1:Class1">
                    <d5p1:Layout xmlns:d6p1="http://schemas.datacontract.org/2004/07/ClassLibrary3">
                        <d6p1:abc>ABCDEF</d6p1:abc>
                        <d6p1:id>11</d6p1:id>
                        <d6p1:name>fromClass1</d6p1:name>
                    </d5p1:Layout>
                    <d5p1:id>11</d5p1:id>
                    <d5p1:message>iamClass1Panel</d5p1:message>
                </d2p1:anyType>
                <d2p1:anyType xmlns:d5p1="http://schemas.datacontract.org/2004/07/ClassLibrary2" i:type="d5p1:Class2">
                    <d5p1:Layout xmlns:d6p1="http://schemas.datacontract.org/2004/07/ClassLibrary3">
                        <d6p1:abc>ABCDEF</d6p1:abc>
                        <d6p1:id>12</d6p1:id>
                        <d6p1:name>fromClass2</d6p1:name>
                    </d5p1:Layout>
                    <d5p1:id>12</d5p1:id>
                    <d5p1:number>11</d5p1:number>
                </d2p1:anyType>
                <d2p1:anyType xmlns:d5p1="http://schemas.datacontract.org/2004/07/ClassLibrary1" i:type="d5p1:Class1">
                    <d5p1:Layout xmlns:d6p1="http://schemas.datacontract.org/2004/07/ClassLibrary3">
                        <d6p1:abc>ABCDEF</d6p1:abc>
                        <d6p1:id>12</d6p1:id>
                        <d6p1:name>fromClass1</d6p1:name>
                    </d5p1:Layout>
                    <d5p1:id>12</d5p1:id>
                    <d5p1:message>iamClass1BisPanel</d5p1:message>
                </d2p1:anyType>
            </d3p1:container>
        </d2p1:anyType>
    </container>
</Plugins>