XmlSerializer: «Тип« Тип »не может использоваться в этом контексте» - PullRequest
3 голосов
/ 10 октября 2010

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


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

Да Развивайтесь

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

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

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

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

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

Ответы [ 3 ]

0 голосов
/ 05 ноября 2010

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

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

0 голосов
/ 10 ноября 2010

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

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

[XmlInclude(typeof(A))]
public class B : A
{
    public int BValue = 2;
}
0 голосов
/ 04 ноября 2010

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

...