简体   繁体   中英

Xml serialization Exception : The type UserQuery+SpecificContentItem was not expected. Use the XmlInclude or SoapInclude

I have a problem on serializing a class to XML. I have created a sample code that runs an shows the error. The class I want to serialize named "ContentContainer", ContentContainer has a collection of items that its type is "ContentItemBase". because my requirements I implemented these classes as follow. but when the code reaches to the part if actual serialization call, serializer throws this exception :

The type UserQuery+SpecificContentItem was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.

I have searched on this problem but my requirements I can't implement the XmlInclude method that mentioned in exception message. is there any solution (Design OR Implementation Tip) for this problem and similar problems?

CODE :

void Main()
{
    var item  = new SpecificContentItem{ Name = "Test", Value = "TestValue" , SpecificField="TestField"};
    var container = new ContentContainer();
    container.Items.Add(item);
    container.Name = "Test Container";
    XmlSerializer ser=  new XmlSerializer(typeof(ContentContainer));
    StringWriter writer = new StringWriter();
    ser.Serialize(writer, container);
    string result = writer.ToString();
}
public abstract class ContentItemBase
{
    public abstract string Name {get; set;}
    public abstract string Value {get; set;}
}

public class SpecificContentItem: ContentItemBase
{
    public string SpecificField {get; set;}
    public override string Name {get; set;}
    public override string Value {get; set;}
}
public class ContentContainer
{
    public ContentContainer()
    {
        Items = new ContentItemCollection();
    }
    public string Name {get;set;}
    public ContentItemCollection Items{get; set;}
}

public class ContentItemCollection : IEnumerable<ContentItemBase>
{
        public SpecificContentItem SpecificItem { get; set; }
        public IEnumerator<ContentItemBase> GetEnumerator()
        {
            if (SpecificItem != null)
                yield return SpecificItem;
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        public void Add(Object obj)
        {
            if (obj is SpecificContentItem)
                SpecificItem = (SpecificContentItem)obj;
        }
}

Creating your serializer as:

XmlSerializer ser = new XmlSerializer(typeof(ContentContainer), 
                            new Type[] { typeof(SpecificContentItem) });

should do the trick.

You can also add a Serialize method to ContentContainer class

public string Serialize()
{
    var types = Items.Select(x => x.GetType()).Distinct().ToArray();
    XmlSerializer ser = new XmlSerializer(typeof(ContentContainer),types);
    StringWriter writer = new StringWriter();
    ser.Serialize(writer, this);
    return writer.ToString();
}

Since the allowed use of XmlInclude seems to be ambiguous, I'm still going to suggest

[XmlInclude(typeof(SpecificContentItem))]
public class ContentItemCollection : IEnumerable<ContentItemBase>
{

as a possible solution. How that applies with your real world situation is a bit more difficult to tell, but I hope it's applicable and works!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM