C#中数据类型的托管
2014-01-21 10:00
309 查看
数据类型分为了值类型和引用类型,再加上存储时的托管与非托管这个.NET新引入的概念,需要保证通信时数据传输的正确性,需要了解下C#与C 两种语言的通信逻辑。
一般来说通信时需要传递的数据主要是以消息头与消息体的两段的形式,而消息头在大多数情况下需要我们自己设计结构体,本来结构体在C#下是值类型,但是当结构体中存在了引用类型的数据时结构体会成为托管类型,但是C 的数据是非托管的,我们需要使用到System.Runtime.interopService命令空间。
先说一下非托管下c#与C 的结构体coding:
C:
点击(此处)折叠或打开
struct head
{
char ID[12];
char NAME[12];
}
C#:
点击(此处)折叠或打开
[StructLayout(LayoutKind.Sequential,CharSet=
CharSet.Unicode)]
struct UsrDBInfo
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=
12)]
public char[] ID;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=
12)]
public char[] name;
}
至于各个关键字的意思含义需要我们使用ctrl k,l以及ctrl k,p去查看
再就是结构体与byte[]之间的转换(借助于非托管内存块IntPtr):
点击(此处)折叠或打开
/*结构与字节数组的转换*/
//数组类型byte[]是托管的,structObj是托管的,structPtr是非托管的
//从struct转换到byte[]
public staticbyte[] StructToBytes(object
structObj)
{
//返回结构体的大小(以字节为单位)
int size=Marshal.SizeOf(structObj);
//分配大小
byte[] bytes=new
byte[size];
//分配结构体大小的内存空间
IntPtr structPtr
= Marshal.AllocHGlobal(size);
try
{
//将结构体拷到分配好的内存空间
//将数据从托管对象structObj封送到非托管内存块structPtr
Marshal.StructureToPtr(structObj, structPtr,false);
//Marshal.StructureToPtr(structObj, structPtr, true);
//将数据从非托管内存指针复制到托管 8 位无符号整数数组
Marshal.Copy(structPtr, bytes, 0,size);
return bytes;
}
finally
{
//释放以前使用 AllocHGlobal 从进程的非托管内存中分配的内存
Marshal.FreeHGlobal(structPtr);
}
}
//返回类型其实没什么用,从bytes转为strType类型的结构体
//从byte[]转换为struct
//使用Info myInfo=(Info)ByteToStruct(bytes, typeof(Info));
public staticobject BytesToStruct(byte[]
bytes,Type strType)
{
//获取结构体的大小(以字节为单位)
int size=Marshal.SizeOf(strType);
//简单的判断(可以去掉)
if (size> bytes.Length)
{
return
null;
}
//从进程的非托管堆中分配内存给structPtr
IntPtr strPtr
= Marshal.AllocHGlobal(size);
try
{
//将数据从一维托管数组bytes复制到非托管内存指针strPtr
Marshal.Copy(bytes, 0, strPtr,size);
//将数据从非托管内存块封送到新分配的指定类型的托管对象
//将内存空间转换为目标结构体
object obj
= Marshal.PtrToStructure(strPtr, strType);
return obj;
}
finally
{
//释放以前使用 AllocHGlobal 从进程的非托管内存中分配的内存
Marshal.FreeHGlobal(strPtr);
}
}
//带模板,从字节数组转化为结构体 public static StructType ConverBytesToStructure<StructType>(byte[] bytesBuffer)
{
// 检查长度
if (bytesBuffer.Length!=Marshal.SizeOf(typeof(StructType)))
{
throw
new ArgumentException("bytesBuffer参数和structObject参数字节长度不一致。");
}
//分配一个未托管类型变量
IntPtr bufferHandler
= Marshal.AllocHGlobal(bytesBuffer.Length);
try
{
//可以直接用copy()方法
for
(int index = 0; index< bytesBuffer.Length; index)
{
Marshal.WriteByte(bufferHandler, index, bytesBuffer[index]);
}
//从非托管类型转化为托管类型变量
StructType structObject =
(StructType)Marshal.PtrToStructure(bufferHandler,typeof(StructType));
return structObject;
}
finally
{
//释放非托管类型变量
Marshal.FreeHGlobal(bufferHandler);
}
}
一般来说通信时需要传递的数据主要是以消息头与消息体的两段的形式,而消息头在大多数情况下需要我们自己设计结构体,本来结构体在C#下是值类型,但是当结构体中存在了引用类型的数据时结构体会成为托管类型,但是C 的数据是非托管的,我们需要使用到System.Runtime.interopService命令空间。
先说一下非托管下c#与C 的结构体coding:
C:
点击(此处)折叠或打开
struct head
{
char ID[12];
char NAME[12];
}
C#:
点击(此处)折叠或打开
[StructLayout(LayoutKind.Sequential,CharSet=
CharSet.Unicode)]
struct UsrDBInfo
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=
12)]
public char[] ID;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=
12)]
public char[] name;
}
至于各个关键字的意思含义需要我们使用ctrl k,l以及ctrl k,p去查看
再就是结构体与byte[]之间的转换(借助于非托管内存块IntPtr):
点击(此处)折叠或打开
/*结构与字节数组的转换*/
//数组类型byte[]是托管的,structObj是托管的,structPtr是非托管的
//从struct转换到byte[]
public staticbyte[] StructToBytes(object
structObj)
{
//返回结构体的大小(以字节为单位)
int size=Marshal.SizeOf(structObj);
//分配大小
byte[] bytes=new
byte[size];
//分配结构体大小的内存空间
IntPtr structPtr
= Marshal.AllocHGlobal(size);
try
{
//将结构体拷到分配好的内存空间
//将数据从托管对象structObj封送到非托管内存块structPtr
Marshal.StructureToPtr(structObj, structPtr,false);
//Marshal.StructureToPtr(structObj, structPtr, true);
//将数据从非托管内存指针复制到托管 8 位无符号整数数组
Marshal.Copy(structPtr, bytes, 0,size);
return bytes;
}
finally
{
//释放以前使用 AllocHGlobal 从进程的非托管内存中分配的内存
Marshal.FreeHGlobal(structPtr);
}
}
//返回类型其实没什么用,从bytes转为strType类型的结构体
//从byte[]转换为struct
//使用Info myInfo=(Info)ByteToStruct(bytes, typeof(Info));
public staticobject BytesToStruct(byte[]
bytes,Type strType)
{
//获取结构体的大小(以字节为单位)
int size=Marshal.SizeOf(strType);
//简单的判断(可以去掉)
if (size> bytes.Length)
{
return
null;
}
//从进程的非托管堆中分配内存给structPtr
IntPtr strPtr
= Marshal.AllocHGlobal(size);
try
{
//将数据从一维托管数组bytes复制到非托管内存指针strPtr
Marshal.Copy(bytes, 0, strPtr,size);
//将数据从非托管内存块封送到新分配的指定类型的托管对象
//将内存空间转换为目标结构体
object obj
= Marshal.PtrToStructure(strPtr, strType);
return obj;
}
finally
{
//释放以前使用 AllocHGlobal 从进程的非托管内存中分配的内存
Marshal.FreeHGlobal(strPtr);
}
}
//带模板,从字节数组转化为结构体 public static StructType ConverBytesToStructure<StructType>(byte[] bytesBuffer)
{
// 检查长度
if (bytesBuffer.Length!=Marshal.SizeOf(typeof(StructType)))
{
throw
new ArgumentException("bytesBuffer参数和structObject参数字节长度不一致。");
}
//分配一个未托管类型变量
IntPtr bufferHandler
= Marshal.AllocHGlobal(bytesBuffer.Length);
try
{
//可以直接用copy()方法
for
(int index = 0; index< bytesBuffer.Length; index)
{
Marshal.WriteByte(bufferHandler, index, bytesBuffer[index]);
}
//从非托管类型转化为托管类型变量
StructType structObject =
(StructType)Marshal.PtrToStructure(bufferHandler,typeof(StructType));
return structObject;
}
finally
{
//释放非托管类型变量
Marshal.FreeHGlobal(bufferHandler);
}
}
相关文章推荐
- Sql2012如何将远程服务器数据库及表、表结构、表数据导入本地数据库 自定义日志记录功能,按日记录,很方便 C#常量和字段以及各种方法的语法总结 类型,对象,线程栈,托管堆在运行时的关系,以及clr如何调用静态方法,实例方法,和虚方法 asp.net webapi 自定义身份验证
- C++托管与C#中的数据类型转换
- 【C#】对“xxxx::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用。
- c# “XXX::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。
- C#内置数据类型
- C#调用非托管C编写DLL的数据类型转换
- C#基础--之数据类型
- C#操作技巧的数据类型之间的转换
- sql server 与C# 中数据类型的对应关系表
- C#基础(二)--数据类型
- C# 数据类型占用的字节数
- C#中通过Type类访问数据类型信息
- 检索01-c#中基本数据类型和引用类型的区别
- C# 语法练习(1): 基本数据类型
- 数据库中与C#中的数据类型对照
- C#基础视频教程2 常见数据类型和属性方法
- C#基础必读 修饰符、关键字、数据类型辨析
- C#中调用Windows API时的数据类型对应关系
- C#基础必读 修饰符、关键字、数据类型辨析
- 数据库中与C#中的数据类型对照