DataContractSerializer – 更改命名空间并反序列化绑定到旧命名空间的文件

我有一个使用DataContractSerializer序列化的数据类。 该类使用[DataContract]属性,没有明确的Namespace声明。 因此,生成的xml文件中的命名空间是基于类的命名空间生成的。

该课程基本上如下:

 namespace XYZ { [DataContract] public class Data { [DataMember(Order = 1)] public string Prop1 { get; set; } [DataMember(Order = 2)] public int Prop2 { get; set; } } } 

…以及生成的xml:

   StringValue 11  

现在我想通过将[DataContract]属性更改为[DataContract(Namespace = "")]来更改类的名称空间(实际上将其删除[DataContract(Namespace = "")] 。 但是,一旦我执行此操作,之前使用原始命名空间序列化的文件不再反序列化。 我收到以下exception:

Error in line 1 position XXX. Expecting element 'Data' from namespace ''.. Encountered 'Element' with name 'Data', namespace 'http://schemas.datacontract.org/2004/07/XYZ'.

这很有道理。 我更改了命名空间。 我很好。 但是,似乎必须有一种方法告诉DataContractSerializer继续并反序列化该数据,即使名称空间不匹配。

一种可能的方法是将序列化程序使用的阅读器包装在将旧名称空间映射到新名称空间的阅读器中,如下所示。 很多代码,但大多是微不足道的。

 public class StackOverflow_11092274 { const string XML = @"  StringValue 11 "; [DataContract(Name = "Data", Namespace = "")] public class Data { [DataMember(Order = 1)] public string Prop1 { get; set; } [DataMember(Order = 2)] public int Prop2 { get; set; } } public class MyReader : XmlReader { XmlReader inner; public MyReader(XmlReader inner) { this.inner = inner; } public override int AttributeCount { get { return inner.AttributeCount; } } public override string BaseURI { get { return inner.BaseURI; } } public override void Close() { inner.Close(); } public override int Depth { get { return inner.Depth; } } public override bool EOF { get { return inner.EOF; } } public override string GetAttribute(int i) { return inner.GetAttribute(i); } public override string GetAttribute(string name, string namespaceURI) { return inner.GetAttribute(name, namespaceURI); } public override string GetAttribute(string name) { return inner.GetAttribute(name); } public override bool IsEmptyElement { get { return inner.IsEmptyElement; } } public override string LocalName { get { return inner.LocalName; } } public override string LookupNamespace(string prefix) { return inner.LookupNamespace(prefix); } public override bool MoveToAttribute(string name, string ns) { return inner.MoveToAttribute(name, ns); } public override bool MoveToAttribute(string name) { return inner.MoveToAttribute(name); } public override bool MoveToElement() { return inner.MoveToElement(); } public override bool MoveToFirstAttribute() { return inner.MoveToFirstAttribute(); } public override bool MoveToNextAttribute() { return inner.MoveToNextAttribute(); } public override XmlNameTable NameTable { get { return inner.NameTable; } } public override string NamespaceURI { get { if (inner.NamespaceURI == "http://schemas.datacontract.org/2004/07/XYZ") { return ""; } else { return inner.NamespaceURI; } } } public override XmlNodeType NodeType { get { return inner.NodeType; } } public override string Prefix { get { return inner.Prefix; } } public override bool Read() { return inner.Read(); } public override bool ReadAttributeValue() { return inner.ReadAttributeValue(); } public override ReadState ReadState { get { return inner.ReadState; } } public override void ResolveEntity() { inner.ResolveEntity(); } public override string Value { get { return inner.Value; } } } public static void Test() { DataContractSerializer dcs = new DataContractSerializer(typeof(Data)); MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(XML)); try { XmlReader r = XmlReader.Create(ms); XmlReader my = new MyReader(r); Data d = (Data)dcs.ReadObject(my); Console.WriteLine("Data[Prop1={0},Prop2={1}]", d.Prop1, d.Prop2); } catch (Exception e) { Console.WriteLine(e); } } }