序列化派生类型的数组 属性 of derived type
Serialize array of derived type property of derived type
我有一个简单的 .Net 框架 C# 控制台应用程序,它序列化一个 class 是派生类型,其中 属性 也是一个派生类型。
派生的 classes 具有与基础 class 相同的名称,但位于不同的命名空间中以防止它们发生冲突。 XmlSerializer
使用的反射似乎不太适用于此。也许有一些方法可以解决我仍然可以使用漂亮名称的基础 class 和使用漂亮名称的 XML 和 XML 结束的属性它将是人类可编辑的)...派生的 classes 的漂亮名称不是必需的(尽管这将是一个奖励)。
XML 看起来像:
<?xml version="1.0" encoding="utf-8"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Details>
<Detail>
<Description>bald</Description>
</Detail>
<Detail>
<Description>red tie</Description>
</Detail>
</Details>
</Person>
但我能无一例外地得到最接近的是 <Detail>
元素所在的位置
<Detail xsi:type="DerivedDetail"> ... </Detail>
必须添加这个 xs:type
属性对于人工可编辑来说不是最好的 XML。
这是通过以下 C# 代码实现的。如果我删除标记的 XmlType
属性,那么元素 应该 在没有 xsi:type
属性的情况下序列化,但我得到一个异常:
InvalidOperationException: Types 'Test.Detail' and 'Test.Xml.Detail' both use the XML type name, 'Detail', from namespace ''. Use XML attributes to specify a unique XML name and/or namespace for the type.
我尝试将派生的 Xml.Detail
class 标记为匿名 XML 类型,但异常显示为:
InvalidOperationException: Cannot include anonymous type 'Test.Xml.Detail'.
我读过很多类似的问题,但还没有遇到任何解决这个问题的方法。
在下面的代码中 Person
是一个抽象 class,它有一个 属性,它是抽象类型 Detail
的数组。这些类型分别由 Xml.Person
和 Xml.Detail
派生。该程序创建一个测试 Xml.Person
对象并尝试序列化它:
using System;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace Test
{
class Program
{
static void Main(string[] args)
{
// Create test details array
var TestDetails = new Xml.Detail[]
{
new Xml.Detail
{
Description = "bald"
},
new Xml.Detail
{
Description = "red tie"
}
};
// create test person object that holds details array
var TestBar = new Xml.Person()
{
Details = TestDetails
};
// serialize the person object
var s = new Xml.Serializer();
var TestOutput = s.Serialize(TestBar);
Console.WriteLine(TestOutput);
}
}
// base classes
public abstract class Person
{
public abstract Detail[] Details { get; set; }
}
public abstract class Detail
{
public abstract string Description { get; set; }
}
namespace Xml
{
// derived classes
[Serializable]
[XmlType(AnonymousType = true)]
[XmlRoot(IsNullable = false)]
public class Person : Test.Person
{
[XmlArrayItem("Detail", typeof(Detail))]
[XmlArray(IsNullable = false)]
public override Test.Detail[] Details { get; set; }
}
// This attribute makes serialization work but also adds the xsi:type attribute
[XmlType("DerivedDetail")]
[Serializable]
public class Detail : Test.Detail
{
public override string Description { get; set; }
}
// class that does serializing work
public class Serializer
{
private static XmlSerializer PersonSerializer =
new XmlSerializer(typeof(Person), new Type[] { typeof(Detail) });
public string Serialize(Test.Person person)
{
string Output = null;
var Stream = new MemoryStream();
var Encoding = new UTF8Encoding(false, true);
using (var Writer = new XmlTextWriter(Stream, Encoding))
{
Writer.Formatting = Formatting.Indented;
PersonSerializer.Serialize(Writer, person);
Output = Encoding.GetString(Stream.ToArray());
}
Stream.Dispose();
return Output;
}
}
}
}
不确定为什么在没有任何成员字段时使用基础 类 而不是接口。无论如何,我假设您希望 Xml.Person
成为抽象 Person
或从抽象 Person
派生的任何 类 的具体实例,而不用 [=21] 装饰抽象 Person
=] 属性。我通过在序列化之前强制抽象 Person
成为 Xml.Person
的具体实例来实现这一点。请将 XmlSerializationProject
替换为 Test
.
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace XmlSerializationProject
{
class Program
{
static void Main(string[] args)
{
// Create test details array
var TestDetails = new Xml.Detail[]
{
new Xml.Detail
{
Description = "bald"
},
new Xml.Detail
{
Description = "red tie"
}
};
// create test person object that holds details array
var TestBar = new Xml.Person()
{
Details = TestDetails
};
// serialize the person object
var s = new Xml.Serializer();
var TestOutput = s.Serialize(TestBar);
Console.WriteLine(TestOutput);
Console.ReadKey();
}
}
// base classes
public abstract class Person
{
public abstract Detail[] Details { get; set; }
}
public abstract class Detail
{
public abstract string Description { get; set; }
}
namespace Xml
{
[Serializable]
[XmlType(AnonymousType = true)]
[XmlRoot(IsNullable = false)]
public class Person : XmlSerializationProject.Person
{
public Person()
{ }
public Person(XmlSerializationProject.Person person)
{
// Deep copy
if (person.Details == null) return;
this.Details = new Detail[person.Details.Length];
for (int i = 0; i < person.Details.Length; i++)
{
this.Details[i] = new Detail { Description = person.Details[i].Description };
}
}
[XmlArray(ElementName = "Details")]
[XmlArrayItem("Detail", typeof(Detail))]
[XmlArrayItem("ODetail", typeof(XmlSerializationProject.Detail))]
public override XmlSerializationProject.Detail[] Details
{
get;
set;
}
}
[Serializable]
public class Detail : XmlSerializationProject.Detail
{
public override string Description { get; set; }
}
// class that does serializing work
public class Serializer
{
private static readonly XmlSerializer PersonSerializer;
private static Serializer()
{
var xmlAttributeOverrides = new XmlAttributeOverrides();
// Change original "Detail" class's element name to "AbstractDetail"
var xmlAttributesOriginalDetail = new XmlAttributes();
xmlAttributesOriginalDetail.XmlType = new XmlTypeAttribute() { TypeName = "AbstractDetail" };
xmlAttributeOverrides.Add(typeof(XmlSerializationProject.Detail), xmlAttributesOriginalDetail);
// Ignore Person.Details array
var xmlAttributesOriginalDetailsArray = new XmlAttributes();
xmlAttributesOriginalDetailsArray.XmlIgnore = true;
xmlAttributeOverrides.Add(typeof(XmlSerializationProject.Person), "Details", xmlAttributesOriginalDetailsArray);
PersonSerializer = new XmlSerializer(
typeof(Person), xmlAttributeOverrides, new Type[] { typeof(Detail) }, new XmlRootAttribute(), "default");
}
public string Serialize(XmlSerializationProject.Person person)
{
return Serialize(new Person(person));
}
public string Serialize(Person person)
{
string Output = null;
var Stream = new MemoryStream();
var Encoding = new UTF8Encoding(false, true);
using (var Writer = new XmlTextWriter(Stream, Encoding))
{
Writer.Formatting = Formatting.Indented;
PersonSerializer.Serialize(Writer, person);
Output = Encoding.GetString(Stream.ToArray());
}
Stream.Dispose();
return Output;
}
}
}
}
我有一个简单的 .Net 框架 C# 控制台应用程序,它序列化一个 class 是派生类型,其中 属性 也是一个派生类型。
派生的 classes 具有与基础 class 相同的名称,但位于不同的命名空间中以防止它们发生冲突。 XmlSerializer
使用的反射似乎不太适用于此。也许有一些方法可以解决我仍然可以使用漂亮名称的基础 class 和使用漂亮名称的 XML 和 XML 结束的属性它将是人类可编辑的)...派生的 classes 的漂亮名称不是必需的(尽管这将是一个奖励)。
XML 看起来像:
<?xml version="1.0" encoding="utf-8"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Details>
<Detail>
<Description>bald</Description>
</Detail>
<Detail>
<Description>red tie</Description>
</Detail>
</Details>
</Person>
但我能无一例外地得到最接近的是 <Detail>
元素所在的位置
<Detail xsi:type="DerivedDetail"> ... </Detail>
必须添加这个 xs:type
属性对于人工可编辑来说不是最好的 XML。
这是通过以下 C# 代码实现的。如果我删除标记的 XmlType
属性,那么元素 应该 在没有 xsi:type
属性的情况下序列化,但我得到一个异常:
InvalidOperationException: Types 'Test.Detail' and 'Test.Xml.Detail' both use the XML type name, 'Detail', from namespace ''. Use XML attributes to specify a unique XML name and/or namespace for the type.
我尝试将派生的 Xml.Detail
class 标记为匿名 XML 类型,但异常显示为:
InvalidOperationException: Cannot include anonymous type 'Test.Xml.Detail'.
我读过很多类似的问题,但还没有遇到任何解决这个问题的方法。
在下面的代码中 Person
是一个抽象 class,它有一个 属性,它是抽象类型 Detail
的数组。这些类型分别由 Xml.Person
和 Xml.Detail
派生。该程序创建一个测试 Xml.Person
对象并尝试序列化它:
using System;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace Test
{
class Program
{
static void Main(string[] args)
{
// Create test details array
var TestDetails = new Xml.Detail[]
{
new Xml.Detail
{
Description = "bald"
},
new Xml.Detail
{
Description = "red tie"
}
};
// create test person object that holds details array
var TestBar = new Xml.Person()
{
Details = TestDetails
};
// serialize the person object
var s = new Xml.Serializer();
var TestOutput = s.Serialize(TestBar);
Console.WriteLine(TestOutput);
}
}
// base classes
public abstract class Person
{
public abstract Detail[] Details { get; set; }
}
public abstract class Detail
{
public abstract string Description { get; set; }
}
namespace Xml
{
// derived classes
[Serializable]
[XmlType(AnonymousType = true)]
[XmlRoot(IsNullable = false)]
public class Person : Test.Person
{
[XmlArrayItem("Detail", typeof(Detail))]
[XmlArray(IsNullable = false)]
public override Test.Detail[] Details { get; set; }
}
// This attribute makes serialization work but also adds the xsi:type attribute
[XmlType("DerivedDetail")]
[Serializable]
public class Detail : Test.Detail
{
public override string Description { get; set; }
}
// class that does serializing work
public class Serializer
{
private static XmlSerializer PersonSerializer =
new XmlSerializer(typeof(Person), new Type[] { typeof(Detail) });
public string Serialize(Test.Person person)
{
string Output = null;
var Stream = new MemoryStream();
var Encoding = new UTF8Encoding(false, true);
using (var Writer = new XmlTextWriter(Stream, Encoding))
{
Writer.Formatting = Formatting.Indented;
PersonSerializer.Serialize(Writer, person);
Output = Encoding.GetString(Stream.ToArray());
}
Stream.Dispose();
return Output;
}
}
}
}
不确定为什么在没有任何成员字段时使用基础 类 而不是接口。无论如何,我假设您希望 Xml.Person
成为抽象 Person
或从抽象 Person
派生的任何 类 的具体实例,而不用 [=21] 装饰抽象 Person
=] 属性。我通过在序列化之前强制抽象 Person
成为 Xml.Person
的具体实例来实现这一点。请将 XmlSerializationProject
替换为 Test
.
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace XmlSerializationProject
{
class Program
{
static void Main(string[] args)
{
// Create test details array
var TestDetails = new Xml.Detail[]
{
new Xml.Detail
{
Description = "bald"
},
new Xml.Detail
{
Description = "red tie"
}
};
// create test person object that holds details array
var TestBar = new Xml.Person()
{
Details = TestDetails
};
// serialize the person object
var s = new Xml.Serializer();
var TestOutput = s.Serialize(TestBar);
Console.WriteLine(TestOutput);
Console.ReadKey();
}
}
// base classes
public abstract class Person
{
public abstract Detail[] Details { get; set; }
}
public abstract class Detail
{
public abstract string Description { get; set; }
}
namespace Xml
{
[Serializable]
[XmlType(AnonymousType = true)]
[XmlRoot(IsNullable = false)]
public class Person : XmlSerializationProject.Person
{
public Person()
{ }
public Person(XmlSerializationProject.Person person)
{
// Deep copy
if (person.Details == null) return;
this.Details = new Detail[person.Details.Length];
for (int i = 0; i < person.Details.Length; i++)
{
this.Details[i] = new Detail { Description = person.Details[i].Description };
}
}
[XmlArray(ElementName = "Details")]
[XmlArrayItem("Detail", typeof(Detail))]
[XmlArrayItem("ODetail", typeof(XmlSerializationProject.Detail))]
public override XmlSerializationProject.Detail[] Details
{
get;
set;
}
}
[Serializable]
public class Detail : XmlSerializationProject.Detail
{
public override string Description { get; set; }
}
// class that does serializing work
public class Serializer
{
private static readonly XmlSerializer PersonSerializer;
private static Serializer()
{
var xmlAttributeOverrides = new XmlAttributeOverrides();
// Change original "Detail" class's element name to "AbstractDetail"
var xmlAttributesOriginalDetail = new XmlAttributes();
xmlAttributesOriginalDetail.XmlType = new XmlTypeAttribute() { TypeName = "AbstractDetail" };
xmlAttributeOverrides.Add(typeof(XmlSerializationProject.Detail), xmlAttributesOriginalDetail);
// Ignore Person.Details array
var xmlAttributesOriginalDetailsArray = new XmlAttributes();
xmlAttributesOriginalDetailsArray.XmlIgnore = true;
xmlAttributeOverrides.Add(typeof(XmlSerializationProject.Person), "Details", xmlAttributesOriginalDetailsArray);
PersonSerializer = new XmlSerializer(
typeof(Person), xmlAttributeOverrides, new Type[] { typeof(Detail) }, new XmlRootAttribute(), "default");
}
public string Serialize(XmlSerializationProject.Person person)
{
return Serialize(new Person(person));
}
public string Serialize(Person person)
{
string Output = null;
var Stream = new MemoryStream();
var Encoding = new UTF8Encoding(false, true);
using (var Writer = new XmlTextWriter(Stream, Encoding))
{
Writer.Formatting = Formatting.Indented;
PersonSerializer.Serialize(Writer, person);
Output = Encoding.GetString(Stream.ToArray());
}
Stream.Dispose();
return Output;
}
}
}
}