c# 对象二进制序列化

Posted

tags:

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

如何定义对象可以实现序列化。
把xx1.obj对象转化为二进制对象,再转换为xx2.obj对象。

var o1=new obj();
byte[] bytes = SerializeObject(o1);
var o2 = (xx2.obj)DeserializeObject(bytes);

namespace xx1

[Serializable]
public class obj

public string name get; set;
public int value get; set;


namespace xx2

[Serializable]
public class obj

public string name get; set;
public int value get; set;


xx1.obj在一个项目中,对象转化为二进制后传输到另一个项目中,转换为对象。xx2.obj在另一个项目

  本质上说,这并不是二进制序列化的问题,甚至不关序列化的问题。

  你想要的是在两个内部结构一致但在不同命名空间(甚至不同项目)的同名类间做类型转换。


  这个问题很常见,因为实际工作中经常会有此类需求,但是我们又不可能手动的把每个字段的值都抄来抄去。


  解决此问题的方法很多,但都逃不开一个关键思想:A不知道B的存在,B不知道A的存在,那么我就找出一个C,只要A和B都能以C的形式表示,那么转换就不是问题。这里的C是概念上的一个标准,用于当做A和B转换的桥梁。


  普遍的解决方法:

    如一楼所说,XmlSerializer序列化器能够将一个可Xml序列化的类A的“内容”部分抽取出来序列化成Xml片段,也能够将其反序列化为一个符合该Xml“格式”的类B。代码如下。

    序列化端:

System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(classA));
System.IO.Stream stream = new System.IO.FileStream(@"c:\\tmp.txt",System.IO.FileMode.OpenOrCreate);
xs.Serialize(stream, new classA  i = 10, s = "hello" );
stream.Dispose();

反序列化端:
 System.Xml.Serialization.XmlSerializer xsb = new System.Xml.Serialization.XmlSerializer(typeof(classA));
 classA b = (classA)xsb.Deserialize(new System.IO.FileStream(@"c:\\tmp.txt", System.IO.FileMode.Open, System.IO.FileAccess.Read));

打开c:\\tmp.txt,我们可以看到中间传输的内容是

<?xml version="1.0"?>
<classA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <i>10</i>
  <s>hello</s>
</classA>

这表明了传输的内容只关注类名和共有属性/字段。所以在反序列化端,只要我们有同样结构的同名类classA,是可以直接从Xml流进行转换的。当然使用内存流、字节流等都是可以的。这里一定要切记三点:同名同结构(指共有字段/属性部分)的两个类,以及只能序列化公有字段和属性,两个类都必须有默认构造方法。


Xml序列化的优点在于只序列化必要部分且消耗较少,常用于序列化DataTable等结构。


2.第二种方法是使用接口。也许你的两个类分处不同的命名空间或者不同项目,但是只要都能访问到同一interface,那么我们可以稍微费点功夫写一个两个都“认识”的接口,通过接口来转换对象。

public interface dataInterface
    
        int iget;set;
        string sget;set;
    
    [Serializable]
    public class classA : dataInterface
    
        public int iget;set;
        public string sget;set;
    
    [Serializable]
    public class classB : dataInterface
    
        public int iget;set
        public string sget;set;
    

如此,不管classA和classB在哪里,只要你认得dataInterface,那么就可以用其来传输、访问和转换。传输的过程相比xml序列化就灵活多了,你可以使用socket、文件、消息、甚至共享内存等等手段来传输,序列化也可以使用万能的二进制序列化,因为你传出和接受的,都是dataInterface对象而已。


序列化端(二进制序列化+文件传输举例):

 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            System.IO.FileStream fs = new System.IO.FileStream(@"c:\\tmp", System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write);
            formatter.Serialize(fs, (new classA  i = 10, s = "hello" ));
            fs.Dispose();

反序列化:

 

dataInterface data = (dataInterface)formatter.Deserialize(new System.IO.FileStream(@"c:\\tmp", System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Read));

此方法优缺点显而易见。优点是无视两个类的位置、无需同名同结构,缺点是有额外工作(写接口)外加反序列化后只能得到接口不能得到classB。额外注意,上例中使用的二进制序列化需要在类上标记[Serializable]。



除此之外还有很多种方法可以做跨域类型转换,但并不常用,这里就不再敖述了。

参考技术A 首先,这个做法应该说不是标准的,序列化的前提,就是要相同类进行序列化与反序列化.但是你所提的需求在某些特殊的场合,的确会碰到,我这里有一个变通的做法,采用 XmlSeriliazer 序列化成xml,在另一端反序列化回来。通过XML,取出类和命名空间的指定。

以上是关于c# 对象二进制序列化的主要内容,如果未能解决你的问题,请参考以下文章

c#如何将object类型序列化为二进制存入SQLSERVER中,并从数据库中读出来并反序列化得到object对象

C# 序列化之二进制

C# 中的 MFC 对象序列化

C# 序列化和反序列

c# sorket序列化反序列化如何如何传接Object?

在维护对象引用的同时序列化 C# 对象