我想在某些属性上忽略与datamember属性序列化对象。
说我有自定义属性myignoredAtamember。
我想要标记的属性对于我的自定义DataconTractSerializer是看不见的,但对于普通的datacontractserializer可见。
我必须使用datacontractserializer,而别无其他。
代码是Silverlight应用。
有人成功地完成了datacontractserializer的子分类?
对您的问题的答案很复杂,以下问题:
-
DataContractSerializer
已密封,因此无法群体检查以检查MyIgnoreDataMember
。 -
使用序列化替代物在序列化过程中将适当的DTO注入您的对象图中,通常是要走的路 - 但是看起来它在Silverlight上不可用,请参阅此答案。
-
DataContractSerializer
不支持ShouldSerialize
模式,如下所述,您不能仅通过回调方法抑制不希望的属性的序列化。
那么,您有什么选择?假设您的对象图看起来如下:
[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
的输出。那么以下可能性是:
如果您只需要消除一些属性,则可以用
EmitDefaultValue = false
标记它们并在某些线程静态为true
时返回默认值,例如:[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 { string sensitiveData; [DataMember(IsRequired = false, EmitDefaultValue = false)] public string SensitiveData { get { if (SerializationState.InCustomSerialization()) return null; return sensitiveData; } set { sensitiveData = value; } } [DataMember] public string PublicData { get; set; } } public static class SerializationState { [ThreadStatic] static bool inCustomSerialization; public static bool InCustomSerialization() { return inCustomSerialization; } public static IDisposable SetInCustomDeserialization(bool value) { return new PushValue<bool>(value, () => inCustomSerialization, b => inCustomSerialization = b); } } public struct PushValue<T> : IDisposable { Action<T> setValue; T oldValue; public PushValue(T value, Func<T> getValue, Action<T> setValue) { if (getValue == null || setValue == null) throw new ArgumentNullException(); this.setValue = setValue; this.oldValue = getValue(); setValue(value); } #region IDisposable Members // By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class. public void Dispose() { if (setValue != null) setValue(oldValue); } #endregion }
然后,当序列化时,执行类似:
using (SerializationState.SetInCustomDeserialization(true)) { // Serialize with data contract serializer. }
老实说。
您可以使用与真实类型相同的合同名称和名称空间制作整个DTO层次结构,并使用诸如AutoMapper之类的东西将真实类映射到DTO,并序列化DTOS:
[DataContract(Name = "Root", Namespace = "http://www.MyNamespace.com")] class RootObjectDTO { [DataMember] public NestedObjectDTO NestedObject { get; set; } } [DataContract(Name = "Nested", Namespace = "http://www.MyNamespace.com")] class NestedObjectDTO { [DataMember] public string PublicData { get; set; } }
如果在Silverlight上没有AutoMapper,则可以使用
DataContractSerializer
本身进行映射,因为合同名称和名称空间是相同的。IE。 - 将真实的根对象序列化到XML字符串(或XDocument
,如下所示),将中间XML序列化到DTO root,然后序列化DTO。您可以使用以下扩展类别序列化到内存中的
XDocument
(可在Silverlight中获得):public static partial class DataContractSerializerHelper { public static XDocument SerializeContractToXDocument<T>(this T obj) { return obj.SerializeContractToXDocument(null); } public static XDocument SerializeContractToXDocument<T>(this T obj, DataContractSerializer serializer) { var doc = new XDocument(); using (var writer = doc.CreateWriter()) { (serializer ?? new DataContractSerializer(obj.GetType())).WriteObject(writer, obj); } return doc; } public static T DeserializeContract<T>(this XDocument doc) { return doc.DeserializeContract<T>(null); } public static T DeserializeContract<T>(this XDocument doc, DataContractSerializer serializer) { if (doc == null) throw new ArgumentNullException(); using (var reader = doc.CreateReader()) { return (T)(serializer ?? new DataContractSerializer(typeof(T))).ReadObject(reader); } } }
接下来,使用XPath查询修剪不希望的元素,然后将
XDocument
序列化为最终的XML表示。最后,如果性能和内存使用优先级,则可以从此答案中使用
ElementSkippingXmlTextWriter
,以便将其写入修剪元素时。