是否可以在序列化期间为类型定义自己的转换?
Is it possible to define your own conversion for a type during serialization?
我在类型上使用 [DataContract]
属性使其可序列化。一些 properties/fields 是我不想按原样序列化的结构类型,但想严格使用自定义类型进行序列化。
如何用类型替换序列化?
当您在 .NET 中使用 [DataContract]
属性时,通常最终会使用 DataContractSerializer. The DataContractSerializer
has a read-only property named DataContractSurrogate
. This property is a IDataContractSurrogate interface. (the read-only property can be set on the constructor or through the DataContractSerializerSettings 类型序列化该类型)
该接口包含在序列化期间将一种类型转换为另一种类型的逻辑。接口提供了 8 个方法,但是在序列化和反序列化期间将一种类型转换为另一种类型,您实际上只需要实现 3 个。这是实现接口的 class 的基本结构,您可以在其中替换您的接口类型和转换逻辑。
internal class SerializerSurrogate : IDataContractSurrogate
{
/// <summary>
/// Identifies a type transformation.
/// </summary>
/// <param name="type">The type being inspected.</param>
/// <returns>The type to transform to. If the same type is used, transform does not happen.</returns>
public Type GetDataContractType(Type type)
{
if (type == typeof(sourceType))
return typeof(targetType);
return type;
}
/// <summary>
/// During serialization, transfrom from sourceType to targetType.
/// </summary>
/// <param name="obj">The object instance.</param>
/// <param name="targetType">The source type.</param>
/// <returns>A new object instance based on targetType.</returns>
public object GetObjectToSerialize(object obj, Type targetType)
{
if (obj is sourceType)
{
// Create instance of targetType from the obj variable which is sourceType
// Set the properties of the targetType, based on the (sourceType)obj variable.
return new targetType();
}
return obj;
}
/// <summary>
/// During deserialization, transform from targetType to sourceType.
/// </summary>
/// <param name="obj">The object instance.</param>
/// <param name="targetType">The target type.</param>
/// <returns>A new object instance based on sourceType.</returns>
public object GetDeserializedObject(object obj, Type targetType)
{
if (obj is targetType)
{
// Create instance of sourceType from the obj variable which is targetType
// Set the properties of the sourceType, based on the (targetType)obj variable.
return new sourceType();
}
return obj;
}
public object GetCustomDataToExport(Type clrType, Type dataContractType)
{
throw new NotImplementedException();
}
public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
{
throw new NotImplementedException();
}
public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
{
throw new NotImplementedException();
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
{
return null;
}
public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
{
return null;
}
}
我在类型上使用 [DataContract]
属性使其可序列化。一些 properties/fields 是我不想按原样序列化的结构类型,但想严格使用自定义类型进行序列化。
如何用类型替换序列化?
当您在 .NET 中使用 [DataContract]
属性时,通常最终会使用 DataContractSerializer. The DataContractSerializer
has a read-only property named DataContractSurrogate
. This property is a IDataContractSurrogate interface. (the read-only property can be set on the constructor or through the DataContractSerializerSettings 类型序列化该类型)
该接口包含在序列化期间将一种类型转换为另一种类型的逻辑。接口提供了 8 个方法,但是在序列化和反序列化期间将一种类型转换为另一种类型,您实际上只需要实现 3 个。这是实现接口的 class 的基本结构,您可以在其中替换您的接口类型和转换逻辑。
internal class SerializerSurrogate : IDataContractSurrogate
{
/// <summary>
/// Identifies a type transformation.
/// </summary>
/// <param name="type">The type being inspected.</param>
/// <returns>The type to transform to. If the same type is used, transform does not happen.</returns>
public Type GetDataContractType(Type type)
{
if (type == typeof(sourceType))
return typeof(targetType);
return type;
}
/// <summary>
/// During serialization, transfrom from sourceType to targetType.
/// </summary>
/// <param name="obj">The object instance.</param>
/// <param name="targetType">The source type.</param>
/// <returns>A new object instance based on targetType.</returns>
public object GetObjectToSerialize(object obj, Type targetType)
{
if (obj is sourceType)
{
// Create instance of targetType from the obj variable which is sourceType
// Set the properties of the targetType, based on the (sourceType)obj variable.
return new targetType();
}
return obj;
}
/// <summary>
/// During deserialization, transform from targetType to sourceType.
/// </summary>
/// <param name="obj">The object instance.</param>
/// <param name="targetType">The target type.</param>
/// <returns>A new object instance based on sourceType.</returns>
public object GetDeserializedObject(object obj, Type targetType)
{
if (obj is targetType)
{
// Create instance of sourceType from the obj variable which is targetType
// Set the properties of the sourceType, based on the (targetType)obj variable.
return new sourceType();
}
return obj;
}
public object GetCustomDataToExport(Type clrType, Type dataContractType)
{
throw new NotImplementedException();
}
public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
{
throw new NotImplementedException();
}
public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
{
throw new NotImplementedException();
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
{
return null;
}
public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
{
return null;
}
}