如何动态选择将序列化哪些继承属性
本文关键字:序列化 继承 属性 选择 何动态 动态 | 更新日期: 2023-09-27 17:51:03
我有一个带有几个属性的基类和三个派生类。
我想序列化一个包含所有三个派生类的对象,但是每个派生类都应该公开与基类不同的一组属性。
我想用XmlAttributeOverrides动态地做到这一点,并尝试了一些不同的方法来做到这一点,但没有真正做到这一点。
[Serializable]
public class A
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
[Serializable]
public class B : A
{
}
[Serializable]
public class C : A
{
}
[Serializable]
public class Container
{
public B B { get; set; }
public C C { get; set; }
}
class Program
{
static void Main(string[] args)
{
MemoryStream memoryStream = new MemoryStream();
StreamWriter encodingWriter = new StreamWriter(memoryStream, Encoding.Unicode);
var xmlWriter = XmlWriter.Create(encodingWriter, new XmlWriterSettings
{
Indent = false,
OmitXmlDeclaration = true,
});
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes attribute = new XmlAttributes();
attribute.XmlIgnore = true;
overrides.Add(typeof(B), "Property1", attribute);
overrides.Add(typeof(C), "Property2", attribute);
var container = new Container
{
B = new B {Property1 = "B property 1", Property2 = "B property 2"},
C = new C {Property1 = "C property 1", Property2 = "C property 2"}
};
var xmlSerializer = new XmlSerializer(typeof(Container), overrides);
xmlSerializer.Serialize(xmlWriter, container);
var result = Encoding.Unicode.GetString(memoryStream.ToArray());
}
}
在上面的代码中,结果字符串将包含B和C中A的所有属性,但我真的希望它只包含B Property2和C Property1(因为我已经为它们设置了XmlIgnore属性)。
我该怎么做?
编辑:期望的XML:
<Container xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><B><Property2>B property 2</Property2></B><C><Property1>C property 1</Property1></C></Container>
实际XML:
<Container xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><B><Property1>B property 1</Property1><Property2>B property 2</Property2></B><C><Property1>C property 1</Property1><Property2>C property 2</Property2></C></Container>
编辑2:以上是一个可视化问题的例子,但我将详细说明为什么我们需要这样做。
我们有一个容器类(如上所述),其中包含不同类型的派生对象(如上所述)。当我们从容器类向其他人公开数据时,我们希望能够只公开某些在其他地方可配置的字段(可能是敏感数据或诸如此类的数据)。
我们使用XmlAttributeOverrides来为公开的属性设置XmlIgnore属性。这对于大多数类型的对象(没有继承)都很有效,但是现在我们需要以不同的方式序列化不同的派生对象(可配置)。
因此,在上面的示例中,某些客户决定将Property1从类B中排除,将Property2从类C中排除,因此我希望XML看起来像上面那样。这并不与上面的代码工作;看起来XmlSerializer使用基类A的属性设置,而不是从各自的派生类B和c中使用属性设置。
很难从您的问题中确切地看出您正在寻找什么样的XML输出,因此我将给出一个示例,您可以根据需要对其进行修改。(编辑:看来我很幸运;下面的示例实现与您编辑的所需XML结果相匹配)
您可以使用鲜为人知的ShouldSerializePROPERTYNAME
方法来动态指示XmlSerializer
忽略属性。例如:
public class A
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public virtual bool ShouldSerializeProperty1()
{
return true;
}
public virtual bool ShouldSerializeProperty2()
{
return true;
}
}
这些方法可以被子类重写以忽略这些属性:
public class B : A
{
public override bool ShouldSerializeProperty1()
{
return false;
}
}
public class C : A
{
public override bool ShouldSerializeProperty2()
{
return false;
}
}
同样,您可以通过Container
分配的其他属性来控制方法的返回值:
public class A
{
public string Property1 { get; set; }
public string Property2 { get; set; }
[XmlIgnore]
internal bool _ShouldSerializeProperty1 = true;
[XmlIgnore]
internal bool _ShouldSerializeProperty2 = true;
public bool ShouldSerializeProperty1()
{
return _ShouldSerializeProperty1;
}
public bool ShouldSerializeProperty2()
{
return _ShouldSerializeProperty2;
}
}
那么当将B
和C
分配给Container
时,您可以设置这些标志:
public class Container
{
private B _B;
public B B
{
get
{
return _B;
}
set
{
if (value != null)
{
value._ShouldSerializeProperty1 = false;
value._ShouldSerializeProperty2 = true;
}
_B = value;
}
}
private C _C;
public C C
{
get
{
return _C;
}
set
{
if (value != null)
{
value._ShouldSerializeProperty1 = true;
value._ShouldSerializeProperty2 = false;
}
_C = value;
}
}
}
这些只是一些例子(我并没有声称在这里使用了最佳实践)来演示如何使用ShouldSerialize
。你可能想让它适应你的特殊用法。
编辑:考虑到你更新的帖子,有另一种可能性,但需要一点额外的工作来定义你的子类和一些DRY违反(虽然序列化,有时这是可以的)。
首先将A
的属性定义为virtual
,并在子类中作为基本包装器覆盖它们:
public class A
{
public virtual string Property1 { get; set; }
public virtual string Property2 { get; set; }
}
public class B : A
{
public override string Property1 { get { return base.Property1; } set { base.Property1 = value; } }
public override string Property2 { get { return base.Property2; } set { base.Property2 = value; } }
}
public class C : A
{
public override string Property1 { get { return base.Property1; } set { base.Property1 = value; } }
public override string Property2 { get { return base.Property2; } set { base.Property2 = value; } }
}
然后,因为(我假设)你正在通过这些配置管理/构建你的XmlSerializer
序列化,包括XmlIgnore
覆盖所有基类的属性:
overrides.Add(typeof(A), "Property1", attribute);
overrides.Add(typeof(A), "Property2", attribute);
然后也包含XmlIgnore
覆盖子类属性,您希望真正忽略:
overrides.Add(typeof(B), "Property2", attribute);
overrides.Add(typeof(C), "Property1", attribute);