这只是声明性序列化的固有限制,其中类型信息未嵌入输出中。
在尝试转换<Flibble Foo="10" />
回
public class Flibble { public object Foo { get; set; } }
序列化程序如何知道它应该是一个int,一个字符串,一个double(还是其他)……
为了使这项工作可行,您有几种选择,但是如果您真正不知道,直到运行时,最简单的方法可能就是使用XmlAttributeOverrides。
遗憾的是,这仅适用于基类,不适用于接口。您能做的最好的事情就是忽略不足以满足您需求的属性。
如果您真的必须使用接口,则可以使用以下三种选择:
隐藏它并在另一个属性中处理
丑陋,令人不快的锅炉板和大量重复,但大多数同类消费者将不必处理该问题:
[XmlIgnore()]
public object Foo { get; set; }
[XmlElement("Foo")]
[EditorVisibile(EditorVisibility.Advanced)]
public string FooSerialized
{
get { }
set { }
}
这可能会成为维护的噩梦...
实现IXmlSerializable
与第一个选项类似,您可以完全控制事物,但是
- 优点
- 您没有令人讨厌的“假”属性。
- 您可以直接与xml结构进行交互以增加灵活性/版本控制
- 缺点
重复劳动的问题与第一个相似。
修改属性以使用包装类型
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();
if (type == "null")
return;
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的想法合并到第一个技术的“ backing”属性中。这样,大多数繁琐的工作都可以为您完成,但是该类的消费者不会因为自省而感到困惑。