如何将 ISerializable 对象序列化为 SOAP 或 Json 或 Xml
How to serialize an ISerializable object into SOAP or Json or Xml
我有一个 ISerializable 的复杂对象,我想将它序列化为一个 XML 文档(我宁愿不更改源代码并添加 XML 序列化属性的节点)。
ISerializable 可以很好地与 BinaryFormatter 配合使用,但是没有标准的方法可以将其序列化为 XML 或 Json。
Json.NET 库确实支持将 ISerializable 对象序列化为 json,但是该实现有一个非常小的问题,那就是 class 的可序列化构造函数应该是 public 以便 Json.net 检测到它(参见 this issue),这确实使 Json.net 无法用于我的情况。
有没有其他方法可以serialize/deserialize ISerializable object to/from xml, Json 或任何其他平面文本格式?
DataContractSerializer
and DataContractJsonSerializer
both support ISerializable
. See Types Supported by the Data Contract Serializer。
例如,考虑以下 class:
[Serializable]
public class SerializableClass : ISerializable
{
readonly int valueField;
public SerializableClass(int valueField)
{
this.valueField = valueField;
}
public int Value { get { return valueField; } }
#region ISerializable Members
protected SerializableClass(SerializationInfo info, StreamingContext context)
{
this.valueField = info.GetInt32("valueField");
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("valueField", valueField);
}
#endregion
}
以及以下辅助方法:
public static partial class DataContractSerializerHelper
{
public static string SerializeXml<T>(T obj, DataContractSerializer serializer = null, XmlWriterSettings settings = null)
{
serializer = serializer ?? new DataContractSerializer(obj.GetType());
using (var textWriter = new StringWriter())
{
settings = settings ?? new XmlWriterSettings { Indent = true, IndentChars = " " };
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
{
serializer.WriteObject(xmlWriter, obj);
}
return textWriter.ToString();
}
}
public static T DeserializeXml<T>(string xml, DataContractSerializer serializer = null)
{
using (var textReader = new StringReader(xml ?? ""))
using (var xmlReader = XmlReader.Create(textReader))
{
return (T)(serializer ?? new DataContractSerializer(typeof(T))).ReadObject(xmlReader);
}
}
}
public static partial class DataContractJsonSerializerHelper
{
private static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
}
public static string SerializeJson<T>(T obj, DataContractJsonSerializer serializer = null)
{
serializer = serializer ?? new DataContractJsonSerializer(obj.GetType());
using (var memory = new MemoryStream())
{
serializer.WriteObject(memory, obj);
memory.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(memory))
{
return reader.ReadToEnd();
}
}
}
public static T DeserializeJson<T>(string json, DataContractJsonSerializer serializer = null)
{
serializer = serializer ?? new DataContractJsonSerializer(typeof(T));
using (var stream = GenerateStreamFromString(json))
{
var obj = serializer.ReadObject(stream);
return (T)obj;
}
}
}
然后
var test = new SerializableClass(42);
var xml = DataContractSerializerHelper.SerializeXml(test);
Debug.WriteLine(xml);
生产
<SerializableClass xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.datacontract.org/2004/07/Question38188639">
<valueField i:type="x:int" xmlns="">42</valueField>
</SerializableClass>
和
var json = DataContractJsonSerializerHelper.SerializeJson(test);
Debug.WriteLine(json);
生产
{"valueField":42}
Json.NET 实际上支持 ISerializable
类型的非公共流序列化构造函数。如需确认,请参阅 DefaultContractResolver.CreateISerializableContract()
.
的源代码
你的实际问题是 ISerializable
type in question is also a collection, and it appears Json.NET uses an array contract in preference to a JsonISerializableContract
for such types, as shown in DefaultContractResolver.CreateContract()
:
if (typeof(IEnumerable).IsAssignableFrom(t))
{
return CreateArrayContract(objectType);
}
if (CanConvertToString(t))
{
return CreateStringContract(objectType);
}
#if !(DOTNET || PORTABLE40 || PORTABLE)
if (!IgnoreSerializableInterface && typeof(ISerializable).IsAssignableFrom(t))
{
return CreateISerializableContract(objectType);
}
#endif
要解决此问题,您可以创建自己的 custom contract resolver 来反转此逻辑:
public class ISerializableCollectionContractResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
var contract = base.CreateContract(objectType);
var underlyingType = Nullable.GetUnderlyingType(objectType) ?? objectType;
if (!IgnoreSerializableInterface
&& typeof(ISerializable).IsAssignableFrom(underlyingType)
&& contract is JsonArrayContract
&& !underlyingType.GetCustomAttributes<JsonContainerAttribute>().Any())
{
contract = CreateISerializableContract(objectType);
}
return contract;
}
}
您的自定义集合现在应该通过它们的 ISerializable
接口序列化。
您可能想要 。
我有一个 ISerializable 的复杂对象,我想将它序列化为一个 XML 文档(我宁愿不更改源代码并添加 XML 序列化属性的节点)。 ISerializable 可以很好地与 BinaryFormatter 配合使用,但是没有标准的方法可以将其序列化为 XML 或 Json。 Json.NET 库确实支持将 ISerializable 对象序列化为 json,但是该实现有一个非常小的问题,那就是 class 的可序列化构造函数应该是 public 以便 Json.net 检测到它(参见 this issue),这确实使 Json.net 无法用于我的情况。
有没有其他方法可以serialize/deserialize ISerializable object to/from xml, Json 或任何其他平面文本格式?
DataContractSerializer
and DataContractJsonSerializer
both support ISerializable
. See Types Supported by the Data Contract Serializer。
例如,考虑以下 class:
[Serializable]
public class SerializableClass : ISerializable
{
readonly int valueField;
public SerializableClass(int valueField)
{
this.valueField = valueField;
}
public int Value { get { return valueField; } }
#region ISerializable Members
protected SerializableClass(SerializationInfo info, StreamingContext context)
{
this.valueField = info.GetInt32("valueField");
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("valueField", valueField);
}
#endregion
}
以及以下辅助方法:
public static partial class DataContractSerializerHelper
{
public static string SerializeXml<T>(T obj, DataContractSerializer serializer = null, XmlWriterSettings settings = null)
{
serializer = serializer ?? new DataContractSerializer(obj.GetType());
using (var textWriter = new StringWriter())
{
settings = settings ?? new XmlWriterSettings { Indent = true, IndentChars = " " };
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
{
serializer.WriteObject(xmlWriter, obj);
}
return textWriter.ToString();
}
}
public static T DeserializeXml<T>(string xml, DataContractSerializer serializer = null)
{
using (var textReader = new StringReader(xml ?? ""))
using (var xmlReader = XmlReader.Create(textReader))
{
return (T)(serializer ?? new DataContractSerializer(typeof(T))).ReadObject(xmlReader);
}
}
}
public static partial class DataContractJsonSerializerHelper
{
private static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
}
public static string SerializeJson<T>(T obj, DataContractJsonSerializer serializer = null)
{
serializer = serializer ?? new DataContractJsonSerializer(obj.GetType());
using (var memory = new MemoryStream())
{
serializer.WriteObject(memory, obj);
memory.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(memory))
{
return reader.ReadToEnd();
}
}
}
public static T DeserializeJson<T>(string json, DataContractJsonSerializer serializer = null)
{
serializer = serializer ?? new DataContractJsonSerializer(typeof(T));
using (var stream = GenerateStreamFromString(json))
{
var obj = serializer.ReadObject(stream);
return (T)obj;
}
}
}
然后
var test = new SerializableClass(42);
var xml = DataContractSerializerHelper.SerializeXml(test);
Debug.WriteLine(xml);
生产
<SerializableClass xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.datacontract.org/2004/07/Question38188639">
<valueField i:type="x:int" xmlns="">42</valueField>
</SerializableClass>
和
var json = DataContractJsonSerializerHelper.SerializeJson(test);
Debug.WriteLine(json);
生产
{"valueField":42}
Json.NET 实际上支持 ISerializable
类型的非公共流序列化构造函数。如需确认,请参阅 DefaultContractResolver.CreateISerializableContract()
.
你的实际问题是 ISerializable
type in question is also a collection, and it appears Json.NET uses an array contract in preference to a JsonISerializableContract
for such types, as shown in DefaultContractResolver.CreateContract()
:
if (typeof(IEnumerable).IsAssignableFrom(t))
{
return CreateArrayContract(objectType);
}
if (CanConvertToString(t))
{
return CreateStringContract(objectType);
}
#if !(DOTNET || PORTABLE40 || PORTABLE)
if (!IgnoreSerializableInterface && typeof(ISerializable).IsAssignableFrom(t))
{
return CreateISerializableContract(objectType);
}
#endif
要解决此问题,您可以创建自己的 custom contract resolver 来反转此逻辑:
public class ISerializableCollectionContractResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
var contract = base.CreateContract(objectType);
var underlyingType = Nullable.GetUnderlyingType(objectType) ?? objectType;
if (!IgnoreSerializableInterface
&& typeof(ISerializable).IsAssignableFrom(underlyingType)
&& contract is JsonArrayContract
&& !underlyingType.GetCustomAttributes<JsonContainerAttribute>().Any())
{
contract = CreateISerializableContract(objectType);
}
return contract;
}
}
您的自定义集合现在应该通过它们的 ISerializable
接口序列化。
您可能想要