c# - 接口(interface)属性的 XML 序列化

标签 c# .net serialization

我想对一个对象进行 XML 序列化,该对象具有(除其他外)IModelObject 类型的属性(这是一个接口(interface))。

public class Example
{
    public IModelObject Model { get; set; }
}

当我尝试序列化此类的对象时,收到以下错误:
“无法序列化 Example 类型的成员 Example.Model,因为它是一个接口(interface)。”

我的理解是接口(interface)无法序列化的问题。但是,具体的 Model 对象类型在运行时是未知的。

用抽象或具体类型替换 IModelObject 接口(interface)并使用 XMLInclude 继承是可能的,但似乎是一个丑陋的解决方法。

有什么建议吗?

最佳答案

这只是声明式序列化的固有限制,其中类型信息未嵌入到输出中。

尝试转换 <Flibble Foo="10" />回到

public class Flibble { public object Foo { get; set; } }

序列化程序如何知道它应该是一个 int、一个字符串、一个 double(或其他东西)...

要完成这项工作,您有多种选择,但如果您真的直到运行时才知道,最简单的方法可能是使用 XmlAttributeOverrides .

遗憾的是,这只适用于基类,不适用于接口(interface)。您能做的最好的事情就是忽略不能满足您需求的属性。

如果你真的必须坚持使用接口(interface),你有三个真正的选择:

隐藏起来,在另一个属性中处理

丑陋、不愉快的样板和大量重复,但该类别的大多数消费者不必处理这个问题:

[XmlIgnore()]
public object Foo { get; set; }

[XmlElement("Foo")]
[EditorVisibile(EditorVisibility.Advanced)]
public string FooSerialized 
{ 
  get { /* code here to convert any type in Foo to string */ } 
  set { /* code to parse out serialized value and make Foo an instance of the proper type*/ } 
}

这很可能成为维护的噩梦......

实现 IXmlSerializable

与第一个选项类似,您可以完全控制事物,但是

  • 优点
    • 您周围没有令人讨厌的“假”属性。
    • 您可以直接与 xml 结构交互,增加灵 active /版本控制
  • 缺点
    • 您可能最终不得不为该类的所有其他属性重新实现轮子

重复劳动的问题与第一个类似。

修改您的属性以使用包装类型

public sealed class XmlAnything<T> : IXmlSerializable
{
    public XmlAnything() {}
    public XmlAnything(T t) { this.Value = t;}
    public T Value {get; set;}

    public void WriteXml (XmlWriter writer)
    {
        if (Value == null)
        {
            writer.WriteAttributeString("type", "null");
            return;
        }
        Type type = this.Value.GetType();
        XmlSerializer serializer = new XmlSerializer(type);
        writer.WriteAttributeString("type", type.AssemblyQualifiedName);
        serializer.Serialize(writer, this.Value);   
    }

    public void ReadXml(XmlReader reader)
    {
        if(!reader.HasAttributes)
            throw new FormatException("expected a type attribute!");
        string type = reader.GetAttribute("type");
        reader.Read(); // consume the value
        if (type == "null")
            return;// leave T at default value
        XmlSerializer serializer = new XmlSerializer(Type.GetType(type));
        this.Value = (T)serializer.Deserialize(reader);
        reader.ReadEndElement();
    }

    public XmlSchema GetSchema() { return(null); }
}

使用它会涉及类似的东西(在项目 P 中):

public namespace P
{
    public interface IFoo {}
    public class RealFoo : IFoo { public int X; }
    public class OtherFoo : IFoo { public double X; }

    public class Flibble
    {
        public XmlAnything<IFoo> Foo;
    }


    public static void Main(string[] args)
    {
        var x = new Flibble();
        x.Foo = new XmlAnything<IFoo>(new RealFoo());
        var s = new XmlSerializer(typeof(Flibble));
        var sw = new StringWriter();
        s.Serialize(sw, x);
        Console.WriteLine(sw);
    }
}

它给你:

<?xml version="1.0" encoding="utf-16"?>
<MainClass 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <Foo type="P.RealFoo, P, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
  <RealFoo>
   <X>0</X>
  </RealFoo>
 </Foo>
</MainClass>

虽然避免了很多样板,但对于类的用户来说显然更麻烦。

一个愉快的媒介可能是将 XmlAnything 想法合并到第一种技术的“支持”属性中。通过这种方式,大部分繁重的工作都是为您完成的,但除了与内省(introspection)混淆之外,该类的消费者不会受到任何影响。

关于c# - 接口(interface)属性的 XML 序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1333864/

相关文章:

ios - 单点触控 : How to serialize a type (like CLLocation) not marked as Serializable?

java - 如何在反序列化之前验证对象流的内容?

c# - 如何避免为我的每个类使用单独的自定义 TypeDescriptor Provider?

c# - 为什么不能为泛型类型推断类型参数?

c# - 如何编写一种方法,根据用户输入打印出主菜供应天数列表?

.net - 我可以让我的服务阻止 Windows 进入休眠状态吗?

.net - VB.NET 无法在带有 Mono 的 Ubuntu 10.04 上运行

.net - 如何在不创建大缓冲区的情况下将大型 .NET 对象图序列化为 SQL Server BLOB?

c# - "The process cannot access the file because it is being used by another process"图片

c# - 使用 PetaPoco 分页映射关系