【问题标题】:Xml serialization Exception : The type UserQuery+SpecificContentItem was not expected. Use the XmlInclude or SoapIncludeXml 序列化异常:类型 UserQuery+SpecificContentItem 不是预期的。使用 XmlInclude 或 SoapInclude
【发布时间】:2012-07-12 08:50:52
【问题描述】:

我在将类序列化为 XML 时遇到问题。我创建了一个运行显示错误的示例代码。我要序列化的类名为“ContentContainer”,ContentContainer 有一个其类型为“ContentItemBase”的项目集合。因为我的要求我实现了这些类如下。但是当代码到达实际序列化调用的部分时,序列化程序会抛出此异常:

类型 UserQuery+SpecificContentItem 不是预期的。使用 XmlInclude 或 SoapInclude 属性来指定不属于的类型 静态已知。

我已经搜索过这个问题,但我的要求是我无法实现异常消息中提到的 XmlInclude 方法。 对于这个问题和类似问题,是否有任何解决方案(设计或实施技巧)?

代码:

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;
        }
}

【问题讨论】:

  • 呃。您不能使用 XmlInclude 的任何特殊原因?
  • 但是,嘿,感谢您使用 LINQPad 来试用您的代码。很少有人真正费心制作能够在这样的工具中正确描述他们的问题的 sn-ps。
  • 谢谢!我在“ContentContainer”类上尝试了 XmlInclude,有什么方法可以在我的“ContentItemCollection”类上使用它吗?
  • 如果你把 [XmlInclude(typeof(SpecificContentItem))] 放在 ContentItemCollection 类上,它至少在我的 linqpad 中会产生奇迹。 =)

标签: c# .net xml-serialization


【解决方案1】:

将您的序列化程序创建为:

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

应该可以解决问题。

您还可以在ContentContainer 类中添加Serialize 方法

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();
}

【讨论】:

  • 此解决方案是否违反了“局部后果”原则?我项目的序列化部分在另一个 dll 中。
  • @L.B.我真的建议您不要使用 XmlSerializer 构造函数的重载,因为它对内存中生成的序列化程序程序集使用 NO 缓存。因此,这将导致性能问题和看不见的内存使用问题,因为它会在每次您调用该构造函数时创建一个新程序集。
  • 如果实例化序列化程序本身被缓存,而不是依赖于幕后的魔法程序集缓存怎么办?
  • @J.Steen 这将是一个很好的解决方案,因为它只会创建一次您将重用的程序集。
【解决方案2】:

由于XmlInclude 的允许使用似乎模棱两可,我还是会建议

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

作为一种可能的解决方案。很难说这如何适用于您的实际情况,但我希望它适用并且有效!

【讨论】:

  • 这在我的实际情况下不起作用。我不知道为什么这在问题的 linqpad 版本中有效.. :|
  • 那么我同意前两个答案,使用 XmlSerializer 的构造函数重载,它接受多个类型参数 - 如果要重用,手动缓存序列化器。
猜你喜欢
  • 2013-11-28
  • 1970-01-01
  • 1970-01-01
  • 2012-08-06
  • 1970-01-01
  • 1970-01-01
  • 2020-07-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多