XmlSerializer:“类型'Type'在此上下文中不可使用”

5
我正在尝试使用XmlSerializer序列化任何类,而不使用XmlInclude属性。通常情况下可以工作,但是在以下代码中我会遇到异常:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Xml.Serialization;

namespace Test
{
    public class ReactObject { }

    public class ReactListObject : ReactObject { }

    public class ReactList<T> : ReactObject, ICollection, IList<T>
    {
        public ReactList() { }

        public virtual void AddRange(IEnumerable<T> values) { }

        [XmlArray(ElementName = "Items", IsNullable = false)]
        public T[] Items
        {
            get { lock (SyncRoot) { return (ItemsList.ToArray()); } }
            set { lock (SyncRoot) { ItemsList = new List<T>(value); } }
        }

        protected List<T> ItemsList = new List<T>();

        public bool IsSynchronized { get { return (true); } }
        public object SyncRoot { get { return (mRootObject); } }

        private object mRootObject = new object();

        public void CopyTo(Array array, int index) { CopyTo(array, index); }

        [XmlIgnore()]
        public T this[int index] {
            get { return (ItemsList[index]); }
            set { ItemsList[index] = value; }
        }

        public int IndexOf(T item) { return (ItemsList.IndexOf(item)); }

        public virtual void Insert(int index, T item) { }

        public virtual void RemoveAt(int index) { }

        public int Count { get { lock (SyncRoot) { return (ItemsList.Count); } } }

        public bool IsReadOnly { get { return (false); } }

        public virtual void Add(T item) { ItemsList.Add(item); }

        public void Clear() { }

        public bool Contains(T item) { return (false); }

        public virtual void CopyTo(T[] array, int arrayIndex) { }

        public virtual bool Remove(T item) { return (false); }

        public IEnumerator<T> GetEnumerator() { return (ItemsList.GetEnumerator()); }

        IEnumerator IEnumerable.GetEnumerator() { return (ItemsList.GetEnumerator()); }
    }

    [XmlInclude(typeof(B))]
    public class A : ReactListObject
    {
        public int AValue = 1;
    }

    public class B : A
    {
        public int BValue = 2;
    }

    public class AList : ReactList<A>
    {

    }

    static class Program
    {
        [STAThread]
        static void Main()
        {
            // NOT good serializer for the type AList
            XmlSerializer ser1 = new XmlSerializer(typeof(ReactObject), new Type[] { typeof(A), typeof(B), typeof(ReactList<A>), typeof(AList) });
            // Good serializer for the type AList
            XmlSerializer ser2 = new XmlSerializer(typeof(ReactList<A>), new Type[] { typeof(A), typeof(B), typeof(AList) });
            AList list = new AList();

            list.Add(new A());
            list.Add(new B());

            using (FileStream mStream = new FileStream("C:\\Test.xml", FileMode.Create)) {
                ser2.Serialize(mStream, list);
            }
            using (FileStream mStream = new FileStream("C:\\Test.xml", FileMode.Create)) {
                ser1.Serialize(mStream, list);
            }
        }
    }
}

抛出的异常是

类型Test.AList不能在此上下文中使用


这是类图,有助于代码阅读

Develop

我想更多地谈谈我试图实现的目标:我希望尽量减少创建XML序列化程序的实例(实际上,每个序列化的类型都有自己的序列化程序;每当需要序列化未包含的类型时,应用程序将重新创建唯一存在的序列化程序。 (*)

在我看来,似乎

  • 可以使用类型为ReactObject的序列化程序对任何ReactObject(和派生类型)进行序列化,直到在派生层次结构中引入通用类为止。序列化程序的额外类型应涵盖所有预期类型。
  • 在基于ReactObject泛型类派生类型的情况下,该类型无法使用类型为ReactObject的序列化程序进行序列化,但可以使用泛型类型的序列化程序进行序列化。

这可能是个问题,因为当我需要反序列化它时,我必须知道序列化对象的类型。相反,要反序列化“非泛型”ReactObject类型,只需使用类型为ReactObject的常规序列化程序即可,无需知道序列化对象的确切类型。

(*) 实际上,我不知道这个目标是否会带来明显的改进。核心问题将是“对于所有(包含的)类型,单个序列化程序程序集是否更好,还是每种类型一个序列化程序程序集更好?


请澄清:您为什么需要知道类型?难道您不知道您正在反序列化的类型,并将结果转换为该类型吗? - Kell
我正在实现一个可插拔的网络服务。插件是通过派生某些类来实现的,而这种派生在编译时是未知的。 - Luca
请提供一个尽可能简化的完整工作示例,以说明问题。 - Darin Dimitrov
我无法重现此问题,即使使用您的类图中的详细信息。请发布一个包含所有类的完整代码片段,以便我们有一些可以编译的内容。 - Pieter van Ginkel
就在一分钟前,我迟到了。我会更新赏金。 - Luca
显示剩余2条评论
3个回答

0

ReactListObject 是否继承自 ReactObjectser1 被实例化以序列化 ReactObject 类型,但从您的代码示例中我只能看出 listReactListObject 类型。


是的,ReactListObject 继承自 ReactObject。list 变量的类型为 AList,它是一个 *ReactList<T>*,它也是一个 ReactObject - Luca
现在变得有些绝望了:将 typeof(ReactListObject) 添加到 ser1 的构造函数中是否有帮助? - batwad

0

序列化方面很容易 - 在获取序列化器时,使用list.GetType()而不是typeof(ReactObject),将返回AList而不是ReactObject,并创建正确的序列化器。如果您担心实例化太多序列化器,您可以始终将它们保存在以类型为键的字典中。

反序列化更难,因为您首先必须知道对象的类型 - 如果无法让调用者告诉您要期望的类型,则需要在尝试反序列化之前读取数据以确定类型。


这正是我实际所做的。ReactObject序列化程序应该能够序列化AList类型,因为该类型包含在额外类型中,但实际上会抛出异常。在接收数据时,我想使用ReactObject序列化程序进行反序列化:这适用于大多数类层次结构,但在上面的示例中失败了...为什么? - Luca
我注意到ReactObject上没有XmlInclude,这可能与此有关。然而,由于插件架构意味着您无法使用XmlInclude,因此我不会担心这个细节 - 无论如何,您都需要手动处理一些事情。 - Tom Clarkson

-1

首先,它不应该是这样的吗:

//[XmlInclude(typeof(B))]
[Serializable]
public class A : ReactListObject
{
    public int AValue = 1;
}

[XmlInclude(typeof(A))]
public class B : A
{
    public int BValue = 2;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接