部分或完整对象序列化 [英] partial or full object serialization

查看:43
本文介绍了部分或完整对象序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下 Student 定义:

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

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

Using C# serialization attributes, how can you apply two different serialization configurations?

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

When the object is passed to the DataContractSerializer, the user could specify "idOnly" (partial) or "full" serialization.

我有两个运行时用例:

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

推荐答案

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

OK, delete the answer for XmlSerializer because you're using DataContractSerializer.

使用 DataContractSerializer 实现此目的的一种方法是使用代理.代理基本上是一个替换类,您可以在序列化、反序列化和创建模式时将其替换为真实"类之一.您可以使用此技巧将完整的 Student 类替换为一个简单的 StudentId 类,具体取决于(例如)某些 ThreadStatic 状态变量,指示是完整的还是部分的学生将被连载.(我使用 ThreadStatic 以防您可能有多个线程并行序列化数据.)

One way you can accomplish this with DataContractSerializer is by use of surrogates. A surrogate basically is a replacement class that you swap in for one of your "real" classes while serializing, deserializing, and creating schemas. You can use this trick to replace your full Student class with a simple StudentId class depending (e.g.) upon the state of some ThreadStatic state variable indicating whether the full or partial student is to be serialized. (I use ThreadStatic in case you might have multiple threads serializing data in parallel.)

这样你的 Student 类就会变成这样:

Thus your Student class would become something like this:

[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.由于您只进行序列化,而不是反序列化或模式生成,因此大多数方法可以保持未实现:

Next you must create a IDataContractSurrogate class telling the DataContractSerializer what replacements to make. In this example you will conditionally replace Student when only the Id is desired. Since you are only doing serialization, not deserialization or schema generation, most methods can remain unimplemented:

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
}

最后,这是一个如何使用它的示例:

And finally, here is an example of how it is used:

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是

In this test case, xml1 is

<?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 序列化为顶级对象,但如果它嵌套在某个类对象图中的深处,则会发生替换.

which is what you seek. Finally, note that, while my test case serializes Student as a top-level object, the replacement will occur if it is nested deep inside some class object graph.

另一个示例,请参见此处:http://blogs.msdn.com/b/carlosfigueira/archive/2011/09/14/wcf-extensibility-serialization-surrogates.aspx

For another example, see here: http://blogs.msdn.com/b/carlosfigueira/archive/2011/09/14/wcf-extensibility-serialization-surrogates.aspx

这篇关于部分或完整对象序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆