C# 自定义数据序列化程序
我想序列化在某些属性上具有要忽略的DataMember属性的对象 假设我有自定义属性MyIgnoreDataMember 我希望标记有它的属性对于自定义DataContractSerializer不可见,但对于普通DataContractSerializer可见 我必须使用DataContractSerializer,其他什么都不用 代码是Silverlight应用程序C# 自定义数据序列化程序,c#,.net,silverlight,serialization,datacontractserializer,automapper,C#,.net,Silverlight,Serialization,Datacontractserializer,Automapper,我想序列化在某些属性上具有要忽略的DataMember属性的对象 假设我有自定义属性MyIgnoreDataMember 我希望标记有它的属性对于自定义DataContractSerializer不可见,但对于普通DataContractSerializer可见 我必须使用DataContractSerializer,其他什么都不用 代码是Silverlight应用程序 有人成功地将DataContractSerializer子类化了吗?以下问题使问题的答案变得复杂: 是密封的,因此无法子类化以
有人成功地将DataContractSerializer子类化了吗?以下问题使问题的答案变得复杂:
MyIgnoreDataMember
的属性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; }
}
您希望有条件地抑制敏感数据的输出。那么以下是可能性:
如果您只需要删除一些属性,那么当某个线程静态为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
}
老实说,相当难看
您可以使用与实际类型相同的合同名称和名称空间创建一个完整的DTO层次结构,使用类似的方法将实际类映射到DTO,并序列化DTO:
[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
本身进行映射,因为契约名称和名称空间是相同的。即-将实际根对象序列化为XML字符串(或序列化为XDocument
,如下所示),将中间XML反序列化为DTO根,然后序列化出DTO
您可以使用以下扩展类序列化到内存中的XDocument
(它):
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);
}
}
}
公共静态部分类DataContractSerializerHelper
{
公共静态XDocument文档(此T对象)
{
返回目标单据(空);
}
公共静态XDocument序列化ContractToxDocument(此T obj,DataContractSerializer序列化程序)
{
var doc=新的XDocument();
使用(var writer=doc.CreateWriter())
{
(serializer??新的DataContractSerializer(obj.GetType()).WriteObject(writer,obj);
}
退货单;
}
公共静态T反序列化契约(此XDocument文档)
{
返回单据反序列化合同(空);
}
公共静态T反序列化契约(此XDocument文档、DataContractSerializer序列化程序)
{
如果(doc==null)
抛出新ArgumentNullException();
使用(var reader=doc.CreateReader())
{
return(T)(序列化程序??新的DataContractSerializer(typeof(T))).ReadObject(reader);
}
}
}
接下来,使用修剪不需要的元素,然后将XDocument
序列化为最终的XML表示形式
最后,如果性能和内存使用都很高,您可以使用ElementSkippingXmlTextWriter
from在编写不需要的元素时删除它们
使用序列化代理通常是一种方法,但是看起来它在Silverlight上是不可用的,请参阅。在缺少数据契约代理的情况下,您可能会考虑一种不同的方法:从代码中使用“EntEngSkpIPxxMLTEXTWRITER < /代码>,并在写入时跳过不需要的元素。所以不能被子类化。@dbc有趣。非常感谢。请把它作为答案贴出来
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);
}
}
}