请教C#下如何序列化自定义结构或类?

问题描述

各位高手:请问在C#中使用Binaryformater将自定义数据结构序列化时,如定义结构structSTData{intnum;chartype;shortarr;doublex;};结构采用单字节对齐方式,序列化后字节的数组比结构实际的字节数要大几倍,如何让序列化后字节数组的大小等于实际结构的字节数?由于需要C#通过UDP与VC6之间进行数据通信,在VC6中结构使用单字节对齐后,转换后的字节数组就是实际结构的字节之和,而如果C#转换后的字节数组大小与VC6的字节数组大小不同就无法确保C#与VC6之间的正常通信。请问如何解决这个问题?

解决方案

解决方案二:
没搞过,帮你顶
解决方案三:
最好自己处理,截取收到的数据包的每个字节,进行相应的转换后给的Struct赋值。别想着偷懒,有时候最笨的办法就是最有效的办法。
解决方案四:
不是序列化数据结构,而是序列化数据。在C#里实现方法:自定义标签,给需要序列化的属性贴上然后用反射的方法读取这个struct或者class,检索贴有此标签的属性,输出到xml流中vc中通过udp传递过去的xml数据流,将数据填充到对应的struct或者class中去
解决方案五:
Binaryformatercouldaddsomemeta-data,sotheserializedresultismorethanthememoryrepresentation.Youmightwanttodothis:[StructLayout(LayoutKind.Sequential,Pack=1)]structSTData{intnum;chartype;shortarr;doublex;};classProgram{staticvoidMain(){STDatadata=newSTData();byte[]buf=newbyte[Marshal.SizeOf(data)];//copySTDataintoabytearray,itiseasierthandirectaccessingapinnedmemoryunsafe{byte*pB=(byte*)&data;for(inti=0;i<buf.Length;i++){buf[i]=pB[i];}}//nowyoumaysendthebufoverUDP}}

解决方案六:
引用4楼gomoku的回复:

Binaryformatercouldaddsomemeta-data,sotheserializedresultismorethanthememoryrepresentation.Youmightwanttodothis:C#code[StructLayout(LayoutKind.Sequential,Pack=1)]structSTData{intnum;chartype;shortarr;doublex;};classProgram{staticvoidMain(){STDatadata=newSTData();byte[]buf=newbyte[M…

定义类似如下的结构和类:[Serializable][StructLayout(LayoutKind.Sequential,Pack=1)]publicstructSTCord{publicdoublex;//publicdoubley;publicbytetype;publicintnum;};[Serializable][StructLayout(LayoutKind.Sequential,Pack=1)]publicclassSTPara{publicbytetype1;//publicint[]fre=newint[5];//publicbytetype2;//};[Serializable][StructLayout(LayoutKind.Sequential,Pack=1)]//publicclassSTChar{publicbytenum;//publicdoubleTime;//publicSTCordPos;//publicintPw;//publicSTParaPara;//publicbytetype;//publicSTTargetCharacter(){Para=newSTPara();}};请教专家:按照您所给的方法确实能够实现将自定义结构转换为byte数组,但还有以下两个问题:第一:如果对于自定义类类型如STChar,对其进行强制类型的转换byte*pB=(byte*)&data将报错“无法获取托管类型的地址和大小,或无法声明指向它的指针”,该如何将类变量STChar转换为byte数组呢?第二:由于是C#与VC6之间进行相互通信,C#又该如何将接收到的byte数组转换为对应的结构或类呢?C#中是否有比较简单的办法实现这些转换,而不需要对每一种自定义类型中的每个变量进行单独的转换后再合成为一个byte数组,否则一旦数据类型较多,转换的工作量会非常大,而且某一数据类型有变化,转换方法也必须做出相应的改变。谢谢!
解决方案七:
自己实现序列化接口,或者序列化抽象类。把所有要序列化的类或结构体转为byte数组传递有两种类,一种是序列化后长度固定的类。可以用更快速的内存copy序列化。#region缓存正文索引类///<summary>///缓存正文索引类///</summary>internalsealedclassFileCacheContentIndex{internallongPassTime=0;//过期时间internallongKey;//模板时间刻度internalbyteFileName=0;//文件名internallongIndexStart=0;//本身的开始位置internalbyteNextFileName=0;//下一个文件名internallongNextIndexStart=0;//下一个本身的开始位置//为0的时候关闭不为0开启internallongContentIndexStart=0;//正文开始位置//为0的时候关闭不为0开启internaluintContentIndexLen=0;//正文的长度internalstringUrlKey=null;//访问路径的key带参数的url路径了。(len32)internalconstintClassLength=TempletCache.uintl+TempletCache.bytel*2+TempletCache.longl*5+32;internalbyteIsChange=0;//是否已经被修改了0没有1已经被修改了这个应该是内存变量,不向文件内记录//===============================================//internalFileCacheContentIndexMFont=null;//内存中上一个正文索引类指向internalFileCacheContentIndexMNext=null;//内存中下一个正文索引类指向internalFileCacheContentIndexFont=null;//上一个正文索引类指向internalFileCacheContentIndexNext=null;//下一个正文索引类指向internalFileCacheContentContent=null;//缓存正文类}#endregion

这样对长度不变的类进行序列化和反序列化#region序列化“缓存正文索引类”internalstaticbyte[]SerializableContent(FileCacheContentIndexFC){byte[]BA=newbyte[FileCacheContentIndex.ClassLength];intl=0;System.Buffer.BlockCopy(System.BitConverter.GetBytes(FC.PassTime),0,BA,l,TempletCache.longl);l+=TempletCache.longl;System.Buffer.BlockCopy(System.BitConverter.GetBytes(FC.Key),0,BA,l,TempletCache.longl);l+=TempletCache.longl;BA[l++]=FC.FileName;System.Buffer.BlockCopy(System.BitConverter.GetBytes(FC.IndexStart),0,BA,l,TempletCache.longl);l+=TempletCache.longl;BA[l++]=FC.NextFileName;System.Buffer.BlockCopy(System.BitConverter.GetBytes(FC.NextIndexStart),0,BA,l,TempletCache.longl);l+=TempletCache.longl;System.Buffer.BlockCopy(System.BitConverter.GetBytes(FC.ContentIndexStart),0,BA,l,TempletCache.longl);l+=TempletCache.longl;System.Buffer.BlockCopy(System.BitConverter.GetBytes(FC.ContentIndexLen),0,BA,l,TempletCache.uintl);l+=TempletCache.uintl;System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(FC.UrlKey),0,BA,l,32);returnBA;}#endregion#region反序列化“缓存正文索引类”internalstaticFileCacheContentIndexInstanceContent(byte[]BA){FileCacheContentIndexMA=newFileCacheContentIndex();byte[]Bn=newbyte[TempletCache.uintl];byte[]Bnlong=newbyte[TempletCache.longl];intl=0;System.Buffer.BlockCopy(BA,l,Bnlong,0,TempletCache.longl);MA.PassTime=System.BitConverter.ToInt64(Bnlong,0);l+=TempletCache.longl;System.Buffer.BlockCopy(BA,l,Bnlong,0,TempletCache.longl);MA.Key=System.BitConverter.ToInt64(Bnlong,0);l+=TempletCache.longl;MA.FileName=BA[l++];System.Buffer.BlockCopy(BA,l,Bnlong,0,TempletCache.longl);MA.IndexStart=System.BitConverter.ToInt64(Bnlong,0);l+=TempletCache.uintl;MA.NextFileName=BA[l++];System.Buffer.BlockCopy(BA,l,Bnlong,0,TempletCache.longl);MA.NextIndexStart=System.BitConverter.ToInt64(Bnlong,0);l+=TempletCache.uintl;System.Buffer.BlockCopy(BA,l,Bnlong,0,TempletCache.longl);MA.ContentIndexStart=System.BitConverter.ToInt64(Bnlong,0);l+=TempletCache.uintl;System.Buffer.BlockCopy(BA,l,Bn,0,TempletCache.uintl);MA.ContentIndexLen=System.BitConverter.ToUInt32(Bn,0);l+=TempletCache.uintl;byte[]Ba1=newbyte[32];System.Buffer.BlockCopy(BA,l,Ba1,0,32);MA.UrlKey=System.Text.Encoding.ASCII.GetString(Ba1);returnMA;}#endregion

序列化后长度不固定的类。就只能实现序列化接口了#region序列化基础抽象类internalabstractclassSerializableAbstractClass{internalabstractvoidLoad(BinaryReaderrdr);internalabstractvoidSave(BinaryWriterwrt);}#endregion#region缓存正文类///<summary>///缓存正文类///</summary>internalsealedclassFileCacheContent:SerializableAbstractClass{internalbyteIsArray=0;//是否有局部缓存1全局2局部internalushortCount=0;//数组的长度internalstringContent=null;//全局正文缓存//局部的时候位空internalstring[]ConArray=null;//局部缓存#region重载实现读函数///<summary>///重载实现读函数///</summary>///<paramname="rdr"></param>internaloverridevoidLoad(BinaryReaderrdr){IsArray=rdr.ReadByte();Count=rdr.ReadUInt16();if(IsArray==1){Content=rdr.ReadString();}else{ConArray=newstring[Count];for(inti=0;i<Count;i++){ConArray[i]=rdr.ReadString();}}}#endregion#region重载实现写函数///<summary>///重载实现写函数///</summary>///<paramname="wrt"></param>internaloverridevoidSave(BinaryWriterwrt){wrt.Write(IsArray);wrt.Write(Count);if(IsArray==1){wrt.Write(Content);}else{for(inti=0;i<ConArray.Length;i++){wrt.Write(ConArray[i]);}}}#endregion}#endregion

这样序列化和反序列化#region变长数据函数internalstaticbyte[]WriteData(SerializableAbstractClassSI){byte[]BA=null;MemoryStreamfs=null;BinaryWriterwrt=null;try{fs=newMemoryStream(500);wrt=newBinaryWriter(fs);SI.Save(wrt);BA=fs.ToArray();returnBA;}catch{returnnewbyte[0];}finally{wrt.Close();fs.Close();}}#endregion#region读数组internalstaticboolReadData(SerializableAbstractClassSI,byte[]BA){MemoryStreamfs=null;BinaryReaderread=null;try{fs=newMemoryStream(BA);read=newBinaryReader(fs);SI.Load(read);returntrue;}catch{returnfalse;}finally{read.Close();fs.Close();}}#endregion

解决方案八:
其实也可以很简单的用结构处理,只是要记得通知数组的大小:classProgram{[StructLayout(LayoutKind.Sequential,Pack=1)]publicstructSTCord{publicdoublex;publicdoubley;publicbytetype;publicintnum;};[StructLayout(LayoutKind.Sequential,Pack=1)]publicstructSTPara{publicbytetype1;[MarshalAs(UnmanagedType.ByValArray,SizeConst=5)]//<-----publicint[]fre;publicbytetype2;};[StructLayout(LayoutKind.Sequential,Pack=1)]publicstructSTChar{publicbytenum;publicdoubleTime;publicSTCordPos;publicintPw;publicSTParaPara;publicbytetype;};staticvoidMain(string[]args){intsize=Marshal.SizeOf(typeof(STChar));//size==57}}

解决方案九:
如果是使用.net二进制序列化,本身就应该由.net进行反序列化,因为这个序列化是.net的标准。如果你是跨语言的序列化建议采用xml序列化形式,例如与java通讯,甚至和VC++,因为这样的序列化对象比较不是简单的内存数据传导,而是一个对象的反序列化实例,即使它是值类型。如果你确实想用二进制的序列化和其他语言的通讯,可以自己完成序列化的过程,但是这个我认为没有比较转换为非托管结构。
解决方案十:
对于结构可以这样处理,对于类变量该如何处理呢?另外C#又如何将接收到的byte数组转换为对应的结构或类呢?感谢yanqing5266的帮助,你的方法还没有试,不知道转换后的字节是否与VC6的memcpy命令转换后的字节数相同,不然不能实现C#与VC6之间的相互通信。谢谢zhujiechang,XML序列化也增加了无数类容,无法用VC6去正确解包,并且影响通信速度。
解决方案十一:
引用7楼gomoku的回复:

其实也可以很简单的用结构处理,只是要记得通知数组的大小:C#codeclassProgram{[StructLayout(LayoutKind.Sequential,Pack=1)]publicstructSTCord{publicdoublex;publicdoubley;publicbytetype;publicintnum;};[StructLayout(LayoutKind.Sequential,Pack=1)]publicstructSTPara{…

对于结构可以这样处理,对于类变量该如何处理呢?另外C#又如何将接收到的byte数组转换为对应的结构或类呢?感谢yanqing5266的帮助,你的方法还没有试,不知道转换后的字节是否与VC6的memcpy命令转换后的字节数相同,不然不能实现C#与VC6之间的相互通信。谢谢zhujiechang,XML序列化也增加了无数类容,无法用VC6去正确解包,并且影响通信速度。

时间: 2024-09-14 04:10:59

请教C#下如何序列化自定义结构或类?的相关文章

跪求C#下如何实现自定义结构或类与BYTE数组之间的相互转换(即数据的打包与解包)?

问题描述 请教C#下如何实现自定义结构或类与BYTE数组之间的相互转换(即数据的打包与解包)?在C#定义类似如下的结构和类:[Serializable][StructLayout(LayoutKind.Sequential,Pack=1)]publicstructSTCord{publicdoublex;//publicdoubley;publicbytetype;publicintnum;};[Serializable][StructLayout(LayoutKind.Sequential,P

请教C#与VC6之间利用UDP/TCP进行数据传输时,如何实现BYTE数组与自定义数据结构或类的相互转换?

问题描述 请教C#下如何实现自定义结构或类与BYTE数组之间的相互转换(即数据的打包与解包)?在C#定义类似如下的结构和类:[Serializable][StructLayout(LayoutKind.Sequential,Pack=1)]publicstructSTCord{publicdoublex;//publicdoubley;publicbytetype;publicintnum;};[Serializable][StructLayout(LayoutKind.Sequential,P

在C#里面调用带有回调函数和自定义结构体的DLL的例程

函数 开发环境: WinXP Pro(SP2英文版) + VS.NET 2003中文版接口库版本: CMPP2.0 API第二版(V2.6) 该例程演示了如何在C#里面调用VC6.0开发的带回调函数的API,而且回调函数的参数包含结构体,使用C#的委托和IntPtr方法实现. 由于我使用C#刚两天,这是我写的第一个C#程序,因此例程写的可能有点粗糙,但是编译和运行完全没有问题. CMPP2.0的API封装成了标准C调用的方法,提供以下三个接口,使用的时候只要有CMPPAPI.dll就可以了. #

下拉框 树形结构选择-EXT 2.0版本实现下拉框树形结构选择实现过程和方法

问题描述 EXT 2.0版本实现下拉框树形结构选择实现过程和方法 最近在用EXT 2.0开发一个项目,涉及到一下下拉框选择管理机构的问题,点击下拉框要求是树形选择机构,单选.多选都行.烦请各位大侠指点迷津,一定要详细点啊,我在网上看了挺多, 但也不是很好用. 我只需要从我的框架结果采用Struts2.0+Spring+Ibatis,我只需要从action中返回数据到 页面js这两个地方的解决办法.谢谢 解决方案 //下拉框 var permissCombox=Ext.create('Ext.fo

小女子求教::怎样引用不同目录下的一个自定义类

问题描述 各位大虾晚上好:我今晚碰到了一个问题,就是怎样引用不同目录下的一个自定义类,我自定义了一个通用数据操作类:dataoperate.cs,一开始,放到了主文件目录下,统一目录下的文件把他实例化的时候没有问题,但是,把他放到我程序里编自定义的一个文件夹app_code下的时候,就报错说是没有引用,必须把他放到app_code外才可以编译通过,这是怎么回事啊?如何解决?谢谢 解决方案 解决方案二:放在App_Code是正确的.注意一下名称空间解决方案三:顶楼上解决方案四:你的开发工具应该是0

微信公众平台-微信开发,编辑模式下创建的自定义菜单,微信会推送数据包给开发者么?求大神解答,急

问题描述 微信开发,编辑模式下创建的自定义菜单,微信会推送数据包给开发者么?求大神解答,急 微信开发,编辑模式下创建的自定义菜单,微信会推送数据包给开发者么?求大神解答,急 解决方案 编辑模式?开发模式吧..开发模式下发布的新信息也会推送给客户 解决方案二: 编辑模式?开发模式吧..开发模式下发布的新信息也会推送给客户

乍样创建自定义结构的数组

问题描述 乍样创建自定义结构的数组,就是数组元素的类型是一个自定义的结构.在线等 解决方案 解决方案二:可以尝试用ArrayList或Hastable

C#.NET中关于结构与类之间的区别

目录  类与结构的实例比较 类与结构的差别 如何选择结构还是类 一.类与结构的示例比较: 结构示例: publicstructPerson {  stringName;  intheight;  intweight;  publicbooloverWeight()  {   //implementsomething  } } 类示例: publicclassTestTime {  inthours;  intminutes;  intseconds;  publicvoidpasstime()

C#学习之结构与类的区别

区别 最近有看到网上面试题提到结构鱼类的区别,遂查看了msdn以及一些网上的资料总结了一下,一做学习之用 C#学习之结构与类的区别数据结构和类实际上都是创建对象的模版,每个对象都包含数据,并提供了处理和访问数据的方法.在语法上,非常相似,主要是使用关键字的区别.对于类和结构,都是使用关键字new来声明实例:这个关键字对象创建对象,并对其进行初始化. 1.值类型和引用类型结构是指类型,指类型在堆栈(栈)上分配地址,C#中的所有基类型都是结构类型(例如:int对应System.Int32结构):类是