首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >自定义DataContractSerializer

自定义DataContractSerializer
EN

Stack Overflow用户
提问于 2017-02-25 19:32:14
回答 1查看 2K关注 0票数 1

我希望序列化一个具有DataMember属性的对象,以便在某些属性上忽略它。

假设我有自定义属性MyIgnoreDataMember。

我希望用它标记的属性对于我的自定义DataContractSerializer是不可见的,但是对于普通的DataContractSerializer是可见的。

而且我必须使用DataContractSerializer和其他任何东西。

代码是Silverlight应用程序。

有人成功地对DataContractSerializer进行了子类化吗?

EN

回答 1

Stack Overflow用户

发布于 2017-02-26 19:13:34

对您的问题的回答因下列问题而变得复杂:

  1. DataContractSerializer是密封的,所以不能用子类来检查像MyIgnoreDataMember这样的属性。
  2. 在序列化过程中使用序列化代理将适当的DTO注入到对象图中通常是可行的方法--但是看起来它在silverlight上是不可用的,参见这个答案
  3. DataContractSerializer不支持ShouldSerialize模式,正如解释的这里那样,所以您不能仅仅通过回调方法来抑制不想要的属性的序列化。

那么,你有什么选择?假设您的对象图如下所示:

代码语言:javascript
复制
[DataContract(Name = "Root", Namespace = "http://www.MyNamespace.com")]
public class RootObject
{
    [DataMember]
    public NestedObject NestedObject { get; set; }
}

[DataContract(Name = "Nested", Namespace = "http://www.MyNamespace.com")]
public class NestedObject
{
    [DataMember]
    public string SensitiveData { get; set; }

    [DataMember]
    public string PublicData { get; set; }
}

您希望有条件地抑制SensitiveData的输出。然后有以下几种可能性:

  1. 如果只需要消除几个属性,则可以使用EmitDefaultValue = false标记它们,并在某些线程静态为true时返回一个默认值,例如: (名称=“根”,命名空间= "http://www.MyNamespace.com")公共类RootObject { DataMember public NestedObject NestedObject { get;set;}DataContract(名称=“嵌套”,命名空间= "http://www.MyNamespace.com")公共类NestedObject { string sensitiveData;DataMember(IsRequired = false,EmitDefaultValue = false)公共字符串SensitiveData { get { if (SerializationState.InCustomSerialization())返回空;返回sensitiveData;} set { sensitiveData = value;} DataMember公共字符串PublicData { get;set;}公共静态类SerializationState { ThreadStatic静态bool inCustomSerialization;公共静态bool InCustomSerialization() {返回inCustomSerialization;} public静态IDisposable SetInCustomDeserialization(bool值){返回新的PushValue (值,() => inCustomSerialization,b => inCustomSerialization = b);}公共结构PushValue: IDisposable { Action setValue;T oldValue;public PushValue(T值,Func getValue,Action setValue) { if (getValue == null ?x setValue setValue null)抛出新的getValue();=;=();setValue(value);} #region IDisposable成员//通过使用一次性结构,我们避免了分配和释放可终结类实例的开销。公开的void (){ if (setValue != null) setValue(oldValue);} 然后,在序列化时,执行如下操作: 使用(SerializationState.SetInCustomDeserialization(true)) { //序列化和数据契约序列化程序。} 老实说挺丑的。
  2. 您可以使用与实际类型相同的契约名称和名称空间创建整个DTO层次结构,使用类似于自动机的内容将真实的类映射到DTO,并序列化DTO: 名称=“根”,名称空间= "http://www.MyNamespace.com")类RootObjectDTO { DataMember public NestedObjectDTO NestedObject { get;set;}}DataContract(名称=“嵌套”,命名空间= "http://www.MyNamespace.com") class NestedObjectDTO“{ DataMember公共字符串PublicData { get;set;}}) 如果silverlight上无法使用automapper,则可以使用DataContractSerializer自己进行映射,因为合同名称和名称空间是相同的。也就是说-将实际的根对象序列化为XML字符串(或XDocument,如下所示),将中间XML反序列化为DTO根,然后序列化出DTO。
  3. 可以使用以下扩展类将其序列化为内存中的XDocument (其中的以silverlight提供。): 公共静态部分类DataContractSerializerHelper {公共静态XDocument SerializeContractToXDocument(此T){返回obj.SerializeContractToXDocument(null);}公共静态XDocument SerializeContractToXDocument(此T,DataContractSerializer序列化程序){ var doc =新XDocument();使用(var null= doc.CreateWriter()) {(序列化器?新DataContractSerializer(obj.GetType())).WriteObject(writer,obj);}返回doc;}公共静态T DeserializeContract(此XDocument文档){返回doc.DeserializeContract( null);}公共静态T DeserializeContract(此XDocument文档,DataContractSerializer序列化程序){ if (doc == null)抛出新ArgumentNullException();使用(var reader = doc.CreateReader()) {返回(T)(序列化程序?新DataContractSerializer(typeof(T))).ReadObject(reader);}} 接下来,使用XPATH查询修剪不想要的元素,然后将XDocument序列化为最终的XDocument表示。
  4. 最后,如果性能和内存的使用处于优势地位,您可以使用ElementSkippingXmlTextWriter这个答案中删除编写时不想要的元素。
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42460674

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档