XmlSerializer: "Тип" Тип "не может использоваться в этом контексте"

Я пытаюсь выяснить, как сериализовать любой класс с помощью 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 не может использоваться в этом контексте


Вот диаграмма классов, чтобы помочь считывать код

Da Develop

Я хотел бы рассказать больше о цели, которую я пытаюсь достичь: я хочу свести к минимуму создание экземпляров XML-сериализаторов (на самом деле каждый тип serialized имеет свой собственный сериализатор, приложение будет воссоздавать только существующее сериализатор каждый раз, когда не включенный тип должен быть сериализован. (*)

Кажется, ИМХО,

  • Можно сериализовать любые ReactObject (и производные типы) с помощью сериализатора типа ReactObject, пока в иерархии деривации не будет введен общий класс. Дополнительные типы сериализатора должны охватывать все ожидаемые типы.
  • В случае типа, полученного из общего класса на основе ReactObject, тип не может быть сериализован с помощью сериализатора типа ReactObject, но с сериализатором родового типа.

Это может быть проблемой, так как я должен знать тип сериализованного объекта, когда мне нужно десериализовать его. Вместо этого для десериализации "неосновного" типа ReactObject достаточно использовать обычный сериализатор типа ReactObject, не зная точного типа сериализованного объекта.

(*) На самом деле я не знаю, что эта цель привела бы к разумным улучшениям. Основной вопрос: ". Лучше ли один сборщик сериализатора для всех (включенных) типов или сборки сериализатора для каждого типа?"

Ответ 1

Наследует ли ReactListObject от ReactObject? ser1 создается для сериализации типов ReactObject, но из вашего образца кода я могу только сказать, что list имеет тип ReactListObject.

Ответ 2

Сессия сериализации проста - вместо использования typeof (ReactObject) при получении сериализатора используйте list.GetType(), который вернет AList, а не ReactObject, и создаст правильный сериализатор. Если вы беспокоитесь о том, что вы создаете слишком много сериализаторов, вы всегда можете хранить их в словаре с ключом по типу.

Десериализация сложнее, так как вам нужно сначала знать тип объекта - если вы не можете заставить вызывающего абонента рассказать вам, какой тип ожидать, вам нужно будет прочитать данные, прежде чем пытаться десериализовать, чтобы определить тип.

Ответ 3

Прежде всего, не должно быть так:

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

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