这只是声明式序列化的一个固有限制,其中类型信息没有嵌入到输出中.
试着把<Flibble Foo="10" />
美元兑换成<Flibble Foo="10" />
美元
public class Flibble { public object Foo { get; set; } }
序列化程序如何知道它应该是int、string、double(或其他东西)...
要实现这一点,您有几个 Select ,但是如果您真的在运行时才知道,最简单的方法可能是使用XmlAttributeOverrides.
遗憾的是,这只适用于基类,而不适用于接口.在那里,您能做的最好的事情就是忽略不能满足您需要的属性.
如果你真的必须继续使用界面,你有三个真正的 Select :
把它藏起来,在另一个地方处理
难看的、令人不快的样板和大量的重复,但这一类的大多数消费者将不必处理这个问题:
[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
与第一种 Select 类似,你完全掌控一切,但
重复工作的问题与第一个类似.
修改属性以使用包装类型
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 idea 与第一种技术的"支持"特性相结合.通过这种方式,大部分繁重的工作都是为您完成的,但除了与内省的混淆之外,这一类的消费者不会受到任何影响.