I'm trying to figure out how to serialize any class using the XmlSerializer, without using the XmlInclude attribute. Generally works, but with the following code I get an exception:
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;
开发者_StackOverflow中文版 }
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);
}
}
}
}
The exception throw is
The type Test.AList may not be used in this context
Here is the class diagram, to aid the code reading
Da DevelopI'd like to spend more words about the goal I'm trying to achieve: I want to minimize the creation of XML serializers instances (actually each type serialized has its own serializer; the application would re-create the only existent serializer each time a not-included type shall be serialized. (*)
It seems, IMHO,
- It's possible to serialize any ReactObject (and derived types) with a serializer of type ReactObject, till a generic class is introduced in the derivation hierarchy. The extra types of the serializer shall cover all expected types.
- In the case a type derived from a generic class based on ReactObject, the type cannot be serialized with a serializer of type ReactObject, but with a serializer of the generic type.
This could be a problem, since I have to know the type of the serialized object when I need to deserialize it. Instead, to deserialize a "non-generic" ReactObject type is sufficient to use the common serializer of type ReactObject, without knowing the exact type of the serialized object.
(*) Actually I don't know this goal would bring sensible improvements. The core question would be "Is it better a single serializer assembly for all (included) types, or a serializer assembly for each type?"
Does ReactListObject
inherit from ReactObject
? ser1
is instantiated to serialize types of ReactObject
, but from your code sample I can only tell that list
is of type ReactListObject
.
The serialization side is easy - instead of using typeof(ReactObject) when getting the serializer, use list.GetType(), which will return AList rather than ReactObject and create the correct serializer. If you are worried about instantiating too many serializers you can always keep them in a dictionary keyed by type.
Deserialization is harder as you have to know the type of object first - if you can't get the caller to tell you what type to expect, you will need to read the data before you try deserializing to determine the type.
First of all should not it be like this:
//[XmlInclude(typeof(B))]
[Serializable]
public class A : ReactListObject
{
public int AValue = 1;
}
[XmlInclude(typeof(A))]
public class B : A
{
public int BValue = 2;
}
精彩评论