部分或完整对象序列化

时间:2014-08-22 21:26:09

标签: c# serialization datacontractserializer

考虑以下Student定义:

public class Student
{
    public Guid Id {get; set;}
    public String FirstName {get; set;}
    public String LastName { get; set; }
}

使用C#序列化属性,如何应用两种不同的序列化配置?

当对象传递给DataContractSerializer时,用户可以指定“idOnly”(部分)或“完整”序列化。

我有两个运行时用例:

  1. 仅序列化Guid
  2. 对象的完整序列化。

2 个答案:

答案 0 :(得分:0)

我不知道你在谈论什么样的序列化。 但是如果你使用BinaryFormatter,那么要走的路是让Student类实现ISerializable。

然后,您可以执行以下操作:

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
  info.AddValue("Id", Id);

  if (SomeCondition)
  {
    info.AddValue("FirstName", FirstName);
    info.AddValue("LastName", LastName);
  }
}

SomeCondition可以在StreamingContext中使用静态(或线程静态)变量或某些信息。

答案 1 :(得分:0)

好的,请删除XmlSerializer的答案,因为您正在使用DataContractSerializer

使用DataContractSerializer完成此操作的一种方法是使用代理。代理人基本上是一个替代课程,你替换你的一个真实的"序列化,反序列化和创建模式时的类。您可以使用此技巧将一个简单的Student类替换为完整的StudentId类,具体取决于(例如)某个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