[英]How to dynamically choose what inherited properties will be serialized?
我有一個基類,有一些屬性和三個派生類。
我想序列化包含所有三個派生類的對象,但每個派生類應該從基類公開一組不同的屬性。
我想用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:上面是一個可視化問題的示例,但我將擴展為什么我們需要這樣做。
我們有一個Container類(如上所述),它包含不同類型的派生對象(如上所述)。 當我們將Container類中的數據公開給其他人時,我們希望能夠公開某些可在其他地方配置的字段(可能是敏感數據或諸如此類的東西)。
我們在XmlAttributeOverrides的幫助下為暴露的屬性設置XmlIgnore屬性。 這適用於大多數類型的對象(沒有繼承),但現在我們需要以不同的方式(可配置)序列化不同的派生對象。
因此,在上面的示例中,一些客戶已決定從類C中排除Property1,從C類中排除Property2,因此我希望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);
這將產生您想要的輸出。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.