C#关于序列化和反序列化

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#关于序列化和反序列化相关的知识,希望对你有一定的参考价值。

我将XML转为实例,报没有 Unicode 字节顺序标记。不能切换到 Unicode这个错,把XML文件内的这一行删掉就正常了,可是写入的时候是会自动生成这一行的,请问怎么解决

工具/原料
Visual Studio(本文使用VS2013,其他版本亦可)。
准备工作和类设计
1
启动VS,新建C# 类库项目,并命名为KTools。

2
添加C# Winform项目,命名为Test,重命名主窗口为MainForm,并设置为启动项。同时在KTools项目添加文件夹Serializer,并在该文件夹中添加3个类:XMLSerializer、SoapSerializer和BinarySerializer,如下图:

3
该类库的设计目标是快速方便,最好把序列化和反序列化的方法做成静态方法,这样就可以省去了实例化的步骤。序列化大体上分为序列化到文件和序列化到流,虽然序列化到流更为通用,但序列化到流的步骤中似乎没有什么可简化的,故我们只讨论序列化到文件。对于序列化到文件,我们需要考虑文件是否存在、写入是否覆盖等,为了方便使用只考虑“存在覆盖”的原则。为了尽可能的避免异常(因为这样使用起来更简单,不必考虑是否会引发异常),我们必须确保对象可序列化、文件存在、反序列化时文件不空等。另外,为了避免反序列化时的类型转化,以及更好的使用类,把序列化和范序列化的方法做成泛型。
END
XML序列化和反序列化
1
XML序列化需要引用名称空间System.Xml.Serialization,序列化代码如下:
public static void Serialize<T>(T o, string filePath)

try

XmlSerializer formatter = new XmlSerializer(typeof(T));
StreamWriter sw = new StreamWriter(filePath, false);
formatter.Serialize(sw, o);
sw.Flush();
sw.Close();

catch (Exception)

2
XML反序列化,代码如下:
public static T DeSerialize<T>(string filePath)

try

XmlSerializer formatter = new XmlSerializer(typeof(T));
StreamReader sr = new StreamReader(filePath);
T o = (T)formatter.Deserialize(sr);
sr.Close();
return o;

catch (Exception)


return default(T);


END
Soap序列化
1
Soap序列化需要名称引用空间System.Runtime.Serialization.Formatters.Soap,并且该dll引用需要手工添加。Soap序列化代码,如下:
public static void Serialize<T>(T o, string filePath)

try

SoapFormatter formatter = new SoapFormatter();
// StreamWriter sw = new StreamWriter(filePath, false);
Stream stream = new FileStream(filePath , FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, o);
stream.Flush();
stream.Close();

catch (Exception)


2
Soap反序列化,代码如下:
public static T DeSerialize<T>(string filePath)

try

SoapFormatter formatter = new SoapFormatter();
// StreamReader sr = new StreamReader(filePath);
Stream destream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
T o = (T)formatter.Deserialize(destream);
destream.Flush();
destream.Close();
return o;

catch (Exception)


return default(T);


END
Binary序列化和反序列化
1
Binary序列化,代码:
public static void Serialize<T>(T o, string filePath)

try

BinaryFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, o);
stream.Flush();
stream.Close();

catch (Exception)


2
Binary反序列化,代码:
public static T DeSerialize<T>(string filePath)

try

BinaryFormatter formatter = new BinaryFormatter();
Stream destream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
T o = (T)formatter.Deserialize(destream);
destream.Flush();
destream.Close();
return o;

catch (Exception)


return default(T);


END
测试
在Test项目中的MainForm窗体中添加两个Button控件,分别命名为“序列化”和“反序列化”,并添加代码:
public partial class MainForm : Form

public MainForm()

InitializeComponent();

private void button1_Click(object sender, EventArgs e)

string str = "Hello world!!!";
KTools.Serializer.XMLSerializer.Serialize<string>(str, "1.txt");
MessageBox.Show("序列化完毕");

private void button2_Click(object sender, EventArgs e)

string str = KTools.Serializer.XMLSerializer.DeSerialize<string>("1.txt");
MessageBox.Show(str);



调试运行,查看结果:
参考技术A 用处就是以文本(二进制/XML)的形式保存/传递你对象的状态了,这样就可以在下次或者在别的地方(互联网上的另一个程序)读取这些文本(二进制/XML)以还原对象的状态。

C# JSON 反序列化

下面的JSON字符串要转为对象比较容易:
JSON字符串:"A":0,"B":1,"C":0,"D":3

[DataContract(Namespace = "XXX")]
public class MyClass

[DataMember(Order = 1)]
public int A get; set;
[DataMember(Order = 2)]
public int B get; set;
[DataMember(Order = 3)]
public int C get; set;
[DataMember(Order = 4)]
public int D get; set;


var ser = new DataContractJsonSerializer(typeof(MyClass));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(JSON字符串));
MyClass myClass1 = (MyClass)ser.ReadObject(ms);

运用以上代码即可成功转换.

问题是,像下边这样的JSON字符串该如何转换
JSON字符串:"112":0,"325":1,"109":4

这样是不可取的:
[DataContract(Namespace = "XXX")]
public class MyClass

[DataMember(Order = 1)]
public int 112 get; set;
[DataMember(Order = 2)]
public int 325 get; set;
[DataMember(Order = 3)]
public int 109 get; set;

因为C#中变量不能以数字开头,而且类似"112":0这样的项不是固定不变的,数量也不固定.试过用SortedList,但不能成功.请有经验的赐教一下.

不固定的意思是说:这一次是"112":0下一次可能就是"113":0或"234243":0等等,无法预知会来个什么.
数量不固定的意思是说:例子中只给出了3个,但也可能是3万个.

个人凭经验觉得这应该是一个字典类,因为字典类可以用任何字符串做KEY,可以容纳任意数量的项.
原来还有JavaScriptSerializer这东西
JavaScriptSerializer能支持SortedList<string, int>
所以问题很简单就解决了,谢谢.

能否再给我上一课,说一下DataContractJsonSerializer与JavaScriptSerializer有什么区别,在哪种情况下选择哪个比较合理,有在网上搜了一下,都是英文的,看不大懂...
---------------------------
感谢【depluin】的解答:
……
DataContractJsonSerializer 可以处理其中的键类型不是字符串的词典,而 JavascriptSerializer 则无法处理,在这一方面前者的功能更为强大。但后者与 JSON 的兼容性更好。

====================================
可惜百度知道没有分配分数的功能,只能将分数给与其中一个,再次感谢两位的帮助!

参考技术A DataContractJsonSerializer 和 JavascriptSerializer 在行为上存在很大差异。例如,DataContractJsonSerializer 将字典表示为键/值对的数组,而 JavascriptSerializer 则将字典表示为实际的 JSON 对象。

在下面的列表中:此字典用 JSON 对象表示:

DataContractJsonSerializer 将其表示为 ["Key":"one","Value":1,"Key":"two","Value":2]

JavascriptSerializer 将其表示为 “one”:1,”two”:2

DataContractJsonSerializer 可以处理其中的键类型不是字符串的词典,而 JavascriptSerializer 则无法处理,在这一方面前者的功能更为强大。但后者与 JSON 的兼容性更好。
参考技术B 不要用DataContract

var serialize = new JavaScriptSerializer();
var obj= serialize.Deserialize<MyClass>(str);

可以"112":0,"325":1,"109":4
str.Replace(",",",");
"["+str+"]"
将Json对象转为HashTable再进行后序列化本回答被提问者采纳

以上是关于C#关于序列化和反序列化的主要内容,如果未能解决你的问题,请参考以下文章

C# JSON 反序列化

C#网络编程学习---序列化和反序列化

c#序列化和反序列化《转载》

使用 SOAP 请求 C# 的 XML 序列化和反序列化

开发者应当熟知的 C# 序列化和反序列化

在C#中序列化和反序列化之间保留xml元素的顺序