我有一个我需要序列化/反序列化的类,我在那里 - 我有序列化功能,导致下面的XML。但是,由于我自己实现IXmlSerializable
,我不确定ReadXml
的实现应该是什么样的,因为SomeGenericClass<T>
是使用基于属性的标记而不是显式实现序列化的如果IXmlSerializable
<?xml version="1.0" encoding="utf-16"?>
<FooContainer FooName="DoSomething">
<SomeGenericClassOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Value="Foobar" Name="firstParam" Description="First Paramater Serialized" />
<SomeGenericClassOfInt32 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Value="10000" Name="nextParam" Description="Second Serialized parameter" />
</FooContainer>
我想将其序列化为以下实例:
public class FooContainer : IList<ISomeGenericClassBase>, IXmlSerializable
{
public string FooName {get;set;}
void IXmlSerializable.WriteXml(XmlWriter writer) {
var serializer = XmlSerializer.FromTypes(new Type[]{SomeGenericBaseClass})[0];
this
.Select(item=>SomeGenericClassBase.ConvertToMe(item))
.ToList()
.ForEach(item=>serializer.Serialize(writer, item));
}
// IList Implementation omitted - wraps a private List<ISomeGenericClassBase>
}
列表将包含以下行中的实例:
public interface ISomeGenericClassBase
{
}
public interface ISomeGenericBaseClass<T> : ISomeGenericBaseClass
{
}
public class SomeGenericClassBase : ISomeGenericClassBase
{
public static SomeGenericClassBase ConvertToMe(ISomeGenericClassBase target) {
return new SomeGenericClassBase() {Property1 = target.Property1; Property2 = target.Property2}
}
public static ISomeGenericBaseClass ExpantToTyped(SomeGenericClassBase target) {
// Implementation omitted - converts a base class instance to a generic instance by working out the generic type from saved data and reconstructing
}
}
public class SomeGenericClass<T> : SomeGenericClassBase, ISomeGenericBaseClass<T>
{
[XmlAttribute]
public string Name {get;set;}
[XmlAttribute]
public string Description{get;set;}
[XmlAttribute]
public T Value {get;set;}
[XmlElement("")]
public T[] ValidOptions {get;set;}
}
编辑:扩展了实施 - 实现了它,它没有正确地说明问题
核心问题是,我希望能够序列化仅实现接口的项目,即使我只返回SomeGenericClassBase
个实例。根据{{1}}方法中使用的方法,我期望该类的使用者在他们的实现中保存足够的数据,这些实现允许将生成的类转换回其原始形式。 。所以,是的,失去了保真度,但这是我可以忍受的,以换取使用接口列表而不是基类列表的灵活性。
答案 0 :(得分:0)
一个解决方案是回避问题(无论如何,IXmlSerializable.ReadXml看起来非常痛苦,例如对于集合)。我最终做的是废弃IXmlSerializable,而是沿着下面的行生成一个类。
请注意,虽然这种方法有效,但如果序列化实例用于序列化以外的任何其他操作,则目前非常容易出错 - 仅在设置或检索SerializationTarget
时才保持同步。设置后,我们将现有参数转换为适当的实例,并将它们添加到可序列化列表中。当它被检索时,如果它为空,我们从当前值中的任何东西膨胀。
但是,如果在创建此对象后FooContainer发生更改,则不会保持该同步,并且序列化的内容将过时。这主要是因为我很懒,并且不想再次实现IList<SomeGenericClassBase>
来覆盖Add
和Remove
方法(尽管这将是更强大的方法)。
public class FooContainerSerializable
{
public FooContainerSerializable() {}
public FooContainerSerializable(FooContainer serializationTarget)
{
this.SerializationTarget = serializationTarget;
}
[XmlIgnore]
public FooContainer SerializationTarget
{
get {
if (_SerializationTarget == null)
{
_SerializationTarget = new FooContainer();
// Copy across extant collection properties here
this.Parameters.ForEach(item=>_SerializationTarget.Add(item));
}
return _SerializationTarget;
}
set {
// Synchronize this entity's entries here
_SerializationTarget = value;
_SerializationTarget.ForEach(item=>this.Parameters.Add(item.Deflate()));
}
}
private FooContainer _SerializationTarget;
[XmlElement]
public string FooName {
get {return this.SerializationTarget.FooName;}
set {this.SerializationTarget.FooName = value;}
}
[XmlElement]
public List<SomeGenericClassBase> Parameters {
get {return _Parameters ?? (_Parameters = new List<SomeGenericClassBase>());}
set {_Parameters = value;}
}
}
答案 1 :(得分:0)
如果您愿意在集合定义中使用抽象类而不是接口,那么这是另一个选项。您还需要使用SomeGenericClassBase
属性声明XmlInclude
的所有派生类型。我认为如果只有少数几种类型可以用于本课程,那就不会太糟糕了。
[XmlRoot(ElementName = "FooContainer")]
public class FooContainer : List<SomeGenericClassBase>
{
[XmlAttribute]
public string FooName { get; set; }
}
[XmlInclude(typeof(SomeGenericClass<string>))]
[XmlInclude(typeof(SomeGenericClass<int>))]
public abstract class SomeGenericClassBase
{
[XmlAttribute]
public string Name { get; set; }
[XmlAttribute]
public string Description { get; set; }
}
public class SomeGenericClass<T> : SomeGenericClassBase
{
[XmlAttribute]
public T Value { get; set; }
[XmlElement]
public T[] ValidOptions { get; set; }
}
class Class1
{
public static void Run()
{
var f = new FooContainer()
{
new SomeGenericClass<string> { Name = "firstParam", Description = "First Paramater Serialized", Value = "Foobar"},
new SomeGenericClass<int> { Name = "nextParam", Description = "Second Serialized parameter", Value = 10000 }
};
f.FooName = "DoSomething";
XmlSerializer serializer = new XmlSerializer(f.GetType());
StringBuilder sb = new StringBuilder();
// Serialize
using (StringWriter writer = new StringWriter(sb))
{
serializer.Serialize(writer, f);
}
Console.WriteLine(sb);
// Deserialize
using(StringReader reader = new StringReader(sb.ToString()))
{
FooContainer f2 = (FooContainer)serializer.Deserialize(reader);
}
}
}
这将序列化为以下XML:
<?xml version="1.0" encoding="utf-16"?>
<FooContainer xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SomeGenericClassBase xsi:type="SomeGenericClassOfString" Name="firstParam" Description="First Paramater Serialized" Value="Foobar" />
<SomeGenericClassBase xsi:type="SomeGenericClassOfInt32" Name="nextParam" Description="Second Serialized parameter" Value="10000" />
</FooContainer>
反序列化保持完全保真。