数组MARSHALLING z
在托管代码和本地代码之间传递数组,是interop marshaling中间比较复杂的一个问题。本文从数组的定义开始,介绍数组marshalling的三种方法,并对blittable类型等概念做进一步的讨论。
当托管代码需要和本地代码互操作时,我们就进入了interop的领域。interop的场景形形色色,不变的是我们需要把数据从一个世界marshal到另一个世界。
在讨论数组marshalling之前,请各位和我一起思考一个问题,什么是数组?之所以要讨论这个问题,原因在于不同的术语在不同的语境中含有不 同的意思。在使用c语言的时候,我认为数组就是一个指针。但是熟悉c#的朋友可能不同意我的观点,数组是System.Array或者Object[]。 我认为,这两种回答都是出自语言领域的正确观点。那么如果有一个项目含有两个模块,一个用本地代码撰写,另一个用托管代码撰写,两者之间的接口要求传递一 个数组,这个”数组”包含着怎样的语义呢?我觉得有两点是很重要的:
1. 如何访问数组元素。就好比c语言中的数组指针,c#中的数组引用,都是访问数组必不可少的线索。
2. 数组的大小。数组的大小不仅仅是System.Array.Length。它还可以包括诸如数组的维数,每个维上的启始边界和结束边界。
.NET在marshal数组的时候,很大程度上也是从以上两点出发,架起托管世界和本地代码之间的桥梁。根据操作的具体数据类型不同,数组marshal又可以分为以下两个大类,三个小类,我们分别介绍:
1. 数组作为参数传递
a) c/c++类型的数组
c类型的数组,也就是由指针指明存储空间首地址的数组,是一个自描述很低的数据结构。尽管有些编译器支持在固定偏移量上写入数组的长度,但是因为各个编译
器处理的具体方法不同,没有一个标准让CLR来参考。所以我们在marshal一个c类型的数组的时候,不得不用其他方法考虑传递数组的大小,有以下两
种:
1) 约定指针数组长度
这种方法需要调用者和被调用者之间有一个约定,给出一个数组长度的固定值。在托管端声明一个interop方法的时候,只需要用SizeConst这个属性,把这个约定告诉CLR。CLR在进行Marshal的时候,会根据这个值,在本地堆上分配相应的空间。
public static extern void Ex([In, Out][MarshalAs(UnmanagedType.LPArray, SizeParamConst=3)]string[] a);
2)通过一个额外的参数指定数组长度
可能有的朋友觉得,约定一个静态的数组长度还不够灵活,希望能够动态的传递数组的长度,从而使得数组marshalling不必受制于固定数组长度的限
制。我们先来看普通的函数调用是如何解决这个问题的:caller和callee通过约定一个额外的参数,来传递数组的长度,这可以被视作是一个调用者和
被调用者的约定。由于marshalling需要clr的参与,那么就需要把这个约定用clr能够理解的方式,进行扩充,形成一个三方约定。CLR,用属
性SizeParamIndex来描述此类约定。
public static extern void Ex2([In, Out][MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]string[] a,int len);
b) SafeArray
SafeArray是COM引入的数据类型,是一个自描述度很高的数据结构。他可以很清楚的告诉用户,该数组的元素类型,数组包含了多少维,每一维的起始
位置和终止位置。所以marshal这类safearray的时候,只需要通过设定属性,告诉CLR,当前array对应的本地代码是safearray
即可。举例如下:
public void DumpSafeArrayStringIn( [In][MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_BSTR)]Object[] array);
大家可以看到,SafeArraySubType可以用来指定数组元素的类型
2. 数组作为字段传递
很久以来,对于interop,一直有这样的评价,简单数据结构的marshalling其实并不复杂,但是一旦进入了struct或者class这种你
中有我,我中有你的层叠数据结构之后,marshalling就成了bug的温床。所以在这里,我们也要提提数组作为struct/class的一个字段
的方法。在这里首先要给这个stuct/class加一个限制,是byval。由于这个限制,大家可以想象的出,CLR在marshal的时候,做的事情
是类似于浅copy的内存复制,所以对数组marshal的时候,也就只支持固定长度的数组marshal。
- public class StructIntArray
- {
- [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
- public int[] array;
- }
数组作为一种常用的数据结构,各种高级语言都提供了相应的支持,在这些高级语言之间交互操作的时候,数组也是传送集合类型数据的重要结构,希望今天的内容能对大家有所帮助。
数组MARSHALLING z的更多相关文章
- 填充Z形二维数组
形如 1 3 4 10 2 5 9 11 6 8 12 15 7 13 14 16 的数组称谓Z形二维数组.填充这样的数组其实只要按照Z形进行行走填充即可,设置一个flag指示方向,行 ...
- hdu_4742_Pinball Game 3D(cdq分治+树状数组)
题目链接:hdu_4742_Pinball Game 3D 题意: 给你n个点,让你求三维的LIS,并且求出有多少种组合能达到LIS. 题解: 求三维的LIS,典型的三维偏序问题,x排序,解决一维,c ...
- js引用类型数组去重-对象标记法
前言 Js数组去重已经有很多种实现方式:包括逐个检索对比(使用Array.property.indexOf),先排序后对比,使用hash表,利用ES6中的Set()等.这些数组去重办法中速度最快的是h ...
- CF #299 div1 B. Tavas and Malekas KMP-next数组
题目链接:http://codeforces.com/contest/536/problem/B 一个原始字符串,一个未知字符串,每一次从pos[i]开始覆盖未知字符串,问最后字符串的形式,以及判断过 ...
- Zepto源码分析之二(新旧版本zepto.Z方法的区别)
在上一节中讲到Z()方法,是在初始化函数init中直接调用zepto.Z() zepto.Z = function(dom, selector) { dom = dom || [] dom.selec ...
- Spark记录-Scala数组/List/Map/Set
import Array._ import scala.collection.mutable.Set object DataStructure { def main(args:Array[String ...
- matlab函数列表(A~Z)【转】
A a abs 绝对值.模.字符的ASCII码值acos 反余弦acosh 反双曲余弦acot 反余切acoth 反双曲余切acsc 反余割acsch 反双曲余割align 启动图形对象几何位置排列工 ...
- Java中数组的创建
Java中数组的使用 1.普通数组变量的定义: //数组 //1.数组是Java中很重要的一部分,今天对数组进行了大致的了解,Java中的数组和C中数组还是有一定的区别的 //以下是总结的几种方法 p ...
- Leetcode6. Z 字形变换
> 简洁易懂讲清原理,讲不清你来打我~ 输入字符串,按下右上下右上排列后输出字符串
jQuery Mobile里都有什么控件? http://api.jquerymobile.com/category/widgets/ jQuery Mobile里slider控件的change事件怎 ...
- Centos7 设置IPtables
entOS 7.0默认使用的是firewall作为防火墙,这里改为iptables防火墙. 1.关闭firewall: systemctl stop firewalld.service #停止fire ...
- PHP 5.6.6 上运行 ecshop 2.7.3 不兼容问题整合
在安装完php在自己的服务器上以后, 发现在静态网页上出现了很多 error. 在网上查找过后发现,大部分问题是因为 PHP发展到PHP5.5版本以后,有了很多细微的变化.而ECSHOP官方更新又太慢 ...
- WPF读书笔记 x名称空间详解(第二天)
每天看一点,每天进步一点. x名称空间映射的是http://schemas.microsoft.com/winfx/2006/xaml,它包含的类均与解析XAML语言关,亦可称为"XAML名 ...
- stm32类型cl、vl、xl、ld、md、hd的含义
- startup_stm32f10x_ld_vl.s: for STM32 Low density Value line devices - startup_stm32f10x_ld.s: for ...
- mvc razor页面的邮箱校验
由于@符号是razor中的关键字,而邮箱校验的正则表达式中需要使用@符号,所以在cshtml页面的代码中直接写js代码进行邮箱校验会报错. 解决方案: 将邮箱校验写在js文件中,在cshtml文件中引 ...
- java三种工厂模式
适用场合: 7.3 工厂模式的适用场合 创建新对象最简单的办法是使用new关键字和具体类.只有在某些场合下,创建和维护对象工厂所带来的额外复杂性才是物有所值.本节概括了这些场合. 7.3.1 动态实现 ...
- NSStringUIImage~NSData的相互转换以及中文转码
中文转码 str = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 图片编码 NSData *data; ...
- ios音频视频资料--备用
视频播放 MediaPlayer.framework MPMoviePlayerViewController VS MPMoviePlayerController MPMoviePlayerViewC ...