将对象序列化为 XElement 并在内存中反序列化
Posted
技术标签:
【中文标题】将对象序列化为 XElement 并在内存中反序列化【英文标题】:Serialize an object to XElement and Deserialize it in memory 【发布时间】:2012-01-12 11:58:43 【问题描述】:我想将一个对象序列化为 XML,但我不想将它保存在磁盘上。我想将它保存在 XElement 变量中(用于与 LINQ 一起使用),然后反序列化回我的对象。
我该怎么做?
【问题讨论】:
请考虑更改接受的答案,因为我在 Abdul 的回复中添加了评论。不要让其他人使用可接受的解决方案,他们最好使用完美的解决方案(Surjit Samra 或 Eren Ersönmez)。 接受的答案不是一个很好的答案 - 它浪费内存分配并假设为 Ascii 编码。 Eren 的回答简单、有效、高性能:***.com/a/28872669/344638 【参考方案1】:您可以使用这两种扩展方法在 XElement 和您的对象之间进行序列化和反序列化。
public static XElement ToXElement<T>(this object obj)
using (var memoryStream = new MemoryStream())
using (TextWriter streamWriter = new StreamWriter(memoryStream))
var xmlSerializer = new XmlSerializer(typeof(T));
xmlSerializer.Serialize(streamWriter, obj);
return XElement.Parse(Encoding.ASCII.GetString(memoryStream.ToArray()));
public static T FromXElement<T>(this XElement xElement)
var xmlSerializer = new XmlSerializer(typeof(T));
return (T)xmlSerializer.Deserialize(xElement.CreateReader());
用法
XElement element = myClass.ToXElement<MyClass>();
var newMyClass = element.FromXElement<MyClass>();
【讨论】:
创建扩展方法的好解决方案。 你应该使用 public static XElement ToXElementStreamWriter
不是默认为Encoding.UTF8
,不是 Encoding.ASCII
?参考:msdn.microsoft.com/en-us/library/wtbhzte9.aspx.
您应该使用Encoding.UTF8
而不是Encoding.ASCII
。否则,如果你有一个像 "На берегу пустынных волн" 这样的字符串属性,这将中断。或者您可以使用 MemoryStream 或 Encoding 显式绕过(请参阅我的答案)。
不知道为什么这个解决方案如此受欢迎。首先,编码是为解析指定的,但不是为写入指定的——这是一个错误,因为 Encoding.Default 可能不是 ASCII。其次,它比@Surjit Samra 的答案效率低 - 你转换对象> XmlDocument > string > byte [] > string > XDocument。他的解决方案改为执行 object > XmlDocument > XDocument 转换。第三,对 System.Object 进行扩展方法是一种非常糟糕的做法——它会在你的智能感知中到处添加这么多垃圾!【参考方案2】:
您可以使用XMLSerialization
XML 序列化是转换对象的公共的过程 属性和字段为串行格式(在本例中为 XML) 储存或运输。 反序列化在其重新创建对象 XML 输出的原始状态。您可以将序列化视为 一种将对象状态保存到流或缓冲区中的方法。为了 例如,ASP.NET 使用 XmlSerializer 类来编码 XML Web 服务消息
和XDocument Represents an XML document
来实现这一点
using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
namespace ConsoleApplication5
public class Person
public int Age get; set;
public string Name get; set;
class Program
static void Main(string[] args)
XmlSerializer xs = new XmlSerializer(typeof(Person));
Person p = new Person();
p.Age = 35;
p.Name = "Arnold";
Console.WriteLine("\n Before serializing...\n");
Console.WriteLine(string.Format("Age = 0 Name = 1", p.Age,p.Name));
XDocument d = new XDocument();
using (XmlWriter xw = d.CreateWriter())
xs.Serialize(xw, p);
// you can use LINQ on elm now
XElement elm = d.Root;
Console.WriteLine("\n From XElement...\n");
elm.Elements().All(e => Console.WriteLine(string.Format("element name 0 , element value 1", e.Name, e.Value)); return true; );
//deserialize back to object
Person pDeserialized = xs.Deserialize((d.CreateReader())) as Person;
Console.WriteLine("\n After deserializing...\n");
Console.WriteLine(string.Format("Age = 0 Name = 1", p.Age, p.Name));
Console.ReadLine();
这里是输出
【讨论】:
我认为您的意思是在反序列化后编写以下内容: Console.WriteLine(string.Format("Age = 0 Name = 1", pDeserialized.Age, pDeserialized.Name)) ;【参考方案3】:(迟到的答案)
序列化:
var doc = new XDocument();
var xmlSerializer = new XmlSerializer(typeof(MyClass));
using (var writer = doc.CreateWriter())
xmlSerializer.Serialize(writer, obj);
// now you can use `doc`(XDocument) or `doc.Root` (XElement)
反序列化:
MyClass obj;
using(var reader = doc.CreateReader())
obj = (MyClass)xmlSerializer.Deserialize(reader);
【讨论】:
【参考方案4】:没有代码分析问题的 ToXelement,与 Abdul Muim 的答案相同,但修复了 CA 问题(CA1004 除外,在这种情况下无法解决,这是设计使然)
public static XElement ToXElement<T>(this object value)
MemoryStream memoryStream = null;
try
memoryStream = new MemoryStream();
using (TextWriter streamWriter = new StreamWriter(memoryStream))
memoryStream = null;
var xmlSerializer = new XmlSerializer(typeof(T));
xmlSerializer.Serialize(streamWriter, value);
return XElement.Parse(Encoding.ASCII.GetString(memoryStream.ToArray()));
finally
if (memoryStream != null)
memoryStream.Dispose();
【讨论】:
不使用using包裹内存流是什么原因?【参考方案5】:怎么样
public static byte[] BinarySerialize(Object obj)
byte[] serializedObject;
MemoryStream ms = new MemoryStream();
BinaryFormatter b = new BinaryFormatter();
try
b.Serialize(ms, obj);
ms.Seek(0, 0);
serializedObject = ms.ToArray();
ms.Close();
return serializedObject;
catch
throw new SerializationException("Failed to serialize. Reason: ");
【讨论】:
catch(一个真正的异常)然后抛出一些新的垃圾异常,它无法传达原始异常的有用信息(“无法序列化。原因:”)是可怕的。只是不要捕捉,或者如果你想要一个假捕捉作为断点,那么只需执行“throw;”。隐藏真正的异常是糟糕的编码。 捕获只是一个示例!!!,因为主要问题是关于序列化以上是关于将对象序列化为 XElement 并在内存中反序列化的主要内容,如果未能解决你的问题,请参考以下文章