部分或全部对象序列化
本文关键字:对象 序列化 全部 | 更新日期: 2023-09-27 18:19:13
考虑以下Student
定义:
public class Student
{
public Guid Id {get; set;}
public String FirstName {get; set;}
public String LastName { get; set; }
}
使用c#序列化属性,如何应用两种不同的序列化配置?
当对象传递给DataContractSerializer
时,用户可以指定"idOnly"(部分)或"full"序列化。
我有两个运行时用例:
- 只序列化Guid
- 对象的完全序列化。
我不知道你说的是哪种序列化。但是如果你使用BinaryFormatter,方法是让Student类实现isserializable。
然后,你可以这样做:
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Id", Id);
if (SomeCondition)
{
info.AddValue("FirstName", FirstName);
info.AddValue("LastName", LastName);
}
}
SomeCondition可以使用静态(或线程静态)变量或StreamingContext中的一些信息。
OK,删除XmlSerializer
的答案,因为您使用的是DataContractSerializer
。
使用DataContractSerializer
完成此任务的一种方法是使用代理。代理基本上是一个替换类,您可以在序列化、反序列化和创建模式时将其替换为一个"真实"类。你可以使用这个技巧用一个简单的StudentId
类替换你的完整的Student
类,这取决于(例如)一些ThreadStatic
状态变量的状态,表明是要序列化完整的还是部分的学生。(我使用ThreadStatic
,以防您可能有多个线程并行序列化数据。)
Student
类将变成如下所示:
[DataContract()]
public class Student
{
[DataMember]
public Guid Id { get; set; }
[DataMember]
public String FirstName { get; set; }
[DataMember]
public String LastName { get; set; }
}
[DataContract()]
public class StudentId
{
[DataMember]
public Guid Id { get; set; }
}
然后你的全局标志:
public static class SerializationFlags
{
[ThreadStatic]
static bool studentGuidOnly;
public static bool StudentGuidOnly
{
get { return studentGuidOnly; }
set { studentGuidOnly = value; }
}
}
接下来,您必须创建一个IDataContractSurrogate
类,告诉DataContractSerializer
要进行哪些替换。在本例中,当只需要Id时,您将有条件地替换Student
。由于您只执行序列化,而不执行反序列化或模式生成,因此大多数方法可以保持未实现状态:
public class StudentSurrogate : IDataContractSurrogate
{
#region IDataContractSurrogate Members
public object GetCustomDataToExport(Type clrType, Type dataContractType)
{
throw new NotImplementedException();
}
public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
{
throw new NotImplementedException();
}
public Type GetDataContractType(Type type)
{
if (type == typeof(Student) && SerializationFlags.StudentGuidOnly)
{
return typeof(StudentId);
}
return type;
}
public object GetDeserializedObject(object obj, Type targetType)
{
throw new NotImplementedException();
}
public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type> customDataTypes)
{
throw new NotImplementedException();
}
public object GetObjectToSerialize(object obj, Type targetType)
{
if (obj != null)
{
var type = obj.GetType();
if (type == typeof(Student) && SerializationFlags.StudentGuidOnly)
{
var surrogate = new StudentId
{
Id = ((Student)obj).Id,
};
return surrogate;
}
}
return obj;
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
{
throw new NotImplementedException();
}
public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
{
throw new NotImplementedException();
}
#endregion
}
最后,这里有一个如何使用它的例子:
public static class DataContractSerializerHelper
{
private static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
}
public static string GetXml<T>(T obj, DataContractSerializer serializer) where T : class
{
using (var textWriter = new StringWriter())
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = " "; // The indentation used in the test string.
using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
{
serializer.WriteObject(xmlWriter, obj);
}
return textWriter.ToString();
}
}
public static string GetXml<T>(T obj) where T : class
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
return GetXml(obj, serializer);
}
}
public static class SurrogateTest
{
public static void Test()
{
Student kid = new Student();
kid.Id = Guid.NewGuid();
kid.FirstName = "foo";
kid.LastName = "bar";
DataContractSerializer dcs = new DataContractSerializer(
typeof(Student),
new Type [] { typeof(StudentId) },
Int32.MaxValue,
false, true, new StudentSurrogate());
SerializationFlags.StudentGuidOnly = false;
string xml1 = DataContractSerializerHelper.GetXml(kid, dcs);
SerializationFlags.StudentGuidOnly = true;
string xml2 = DataContractSerializerHelper.GetXml(kid, dcs);
}
}
在这个测试用例中,xml1是
<?xml version="1.0" encoding="utf-16"?>
<Student xmlns:i="http://www.w3.org/2001/XMLSchema-instance" z:Id="1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<FirstName z:Id="2">foo</FirstName>
<Id>fa98b508-2fe9-4a09-b551-ba2ed1f70b70</Id>
<LastName z:Id="3">bar</LastName>
</Student>
和xml2是
<?xml version="1.0" encoding="utf-16"?>
<Student xmlns:i="http://www.w3.org/2001/XMLSchema-instance" z:Id="1" xmlns="" i:type="StudentId" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Id>fa98b508-2fe9-4a09-b551-ba2ed1f70b70</Id>
</Student>
就是你要找的。最后,请注意,虽然我的测试用例将Student
序列化为顶级对象,但如果它嵌套在某个类对象图的深处,则会发生替换。
另一个例子,见这里:http://blogs.msdn.com/b/carlosfigueira/archive/2011/09/14/wcf-extensibility-serialization-surrogates.aspx