接口属性的XML序列化 [英] XML serialization of interface property

查看:173
本文介绍了接口属性的XML序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想为XML序列化一个对象,有(其中包括)类型的属性的 IModelObject 的(这是一个接口)。

I would like to XML serialize an object that has (among other) a property of type IModelObject (which is an interface).

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

当我试图序列化这个类的一个对象,我收到以下错误:
无法序列类型的实例成员Example.Model,因为它是一个接口。

When I try to serialize an object of this class, I receive the following error:
"Cannot serialize member Example.Model of type Example because it is an interface."

据我所知,这个问题是,一个接口不能被序列化。但是,具体的型号的对象类型是未知的,直到运行时。

I understand that the problem is that an interface cannot be serialized. However, the concrete Model object type is unknown until runtime.

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

Replacing the IModelObject interface with an abstract or concrete type and use inheritance with XMLInclude is possible, but seems like an ugly workaround.

有什么建议?

推荐答案

这是声明串行化的简单的固有限制,其中没有嵌入在输出中的类型信息。

This is simply an inherent limitation of declarative serialization where type information is not embedded within the output.

在尝试转换< Flibble富=10/>

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

如何串行知道它应该是一个int,一个字符串,双(或其他)...

How does the serializer know whether it should be an int, a string, a double (or something else)...

为使这项工作,你有多种选择,但如果你真的不知道,直到运行时要做到这一点最简单的方法很可能是使用<一个href="http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlattributeoverrides.aspx">XmlAttributeOverrides.

To make this work you have several options but if you truly don't know till runtime the easiest way to do this is likely to be using the XmlAttributeOverrides.

可悲的是,这将只与基类,而不是接口工作。你能做的最好是有忽视它无法满足您的需求属性。

Sadly this will only work with base classes, not interfaces. The best you can do there is to ignore the property which isn't sufficient for your needs.

如果你真的必须留在接口有三个真正的选择:

If you really must stay with interfaces you have three real options:

丑陋的,不愉快的锅炉板和很多重复,但大多数消费者的类不会有要处理的问题:

Ugly, unpleasant boiler plate and much repetition but most consumers of the class will not have to deal with the problem:

[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 of get and make an instance of the proper type*/ } 
}

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

This is likely to become a maintenance nightmare...

相似,在你完全控制事物的第一选择,但

Similar to the first option in that you take full control of things but

  • 赞成
    • 您没有讨厌的'假'的属性游逛。
    • 您可以直接与XML结构交互增加了灵活性/版本
    • Pros
      • You don't have nasty 'fake' properties hanging around.
      • you can interact directly with the xml structure adding flexibility/versioning
      • 您可能最终不得不重新实现的类
      • 该轮所有其他属性

      问题类似于第一。

      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):

      Using this would involve something like (in project 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>
      

      这显然是对类的用户比较繁琐,虽然避免了很多锅炉板。

      This is obviously more cumbersome for users of the class though avoids much boiler plate.

      有一个折中的办法可能是合并XmlAnything想法进入第一个技术的'后盾'属性。通过这种方式最繁重的工作是为你做了,但消费者的阶级遭受超越混乱没有影响与反思。

      A happy medium may be merging the XmlAnything idea into the 'backing' property of the first technique. In this way most of the grunt work is done for you but consumers of the class suffer no impact beyond confusion with introspection.

      这篇关于接口属性的XML序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆