我正在调用IDiaSourceFile::get_checksum
成员函数,该函数具有以下自动生成的.NET签名:
void get_checksum(uint cbData, out uint pcbData, byte[] pbData);
请注意,参数pbData
是out参数。当有人打电话给get_checksum
时,我是否需要担心固定在这里传入的数组?
(背景:
我继承了一些看起来像这样的代码:
unsafe
{
fixed (byte* p = scratch_hash)
{
sourceFile.get_checksum(c, out c, scratch_hash);
}
}
将scratch_hash
定位为p
,然后实际上从不使用p
。我之前没见过这样的东西,并给出了周围代码的状态我怀疑这里的引脚是完全没必要的
)
答案 0 :(得分:2)
根据目前的定义:
void get_checksum(uint cbData, out uint pcbData, byte[] pbData);
您无需固定pbData
。但是,您需要为返回的数据预先分配一个数组,但事先并不知道大小。如果通过cbData
传递的数组大小不够大,并且您当前的方法签名不允许找出缓冲区大小,则该方法将失败。
HRESULT get_checksum (
DWORD cbData,
DWORD* pcbData,
BYTE data[]
);
data [in,out]填充校验和字节的缓冲区。如果 此参数为NULL,然后pcbData返回字节数 必需的。
因此,更有效的方法可能是声明并使用它:
void get_checksum(
uint cbData,
out uint pcbData,
IntPtr data);
// get size
uint size;
obj.get_checksum(0, out size, IntPtr.Zero);
// get data
var buff = new byte[size];
unsafe
{
fixed (byte* p = buff)
{
uint cbData;
obj.get_checksum(size, out cbData, (IntPtr)p);
if (size != cbData)
throw new InvalidOperationException("cbData");
}
}
如果您不想(或不能)使用unsafe
代码,可以选择以下代码:
// get size
uint size;
obj.get_checksum(0, out size, IntPtr.Zero);
// get the data
byte[] buff;
var p = Marshal.AllocHGlobal((int)size);
try
{
uint cbData;
obj.get_checksum(size, out cbData, p);
if (size < cbData)
throw new InvalidOperationException("cbData");
buff = new byte[cbData];
Marshal.Copy(p, buff, 0, (int)cbData);
}
finally
{
Marshal.FreeHGlobal(p);
}
答案 1 :(得分:0)
不,在这种情况下你不必这样做 - 你甚至不能这样做。
但是,如果遇到性能问题,可能需要更改该签名,因为编组器会将字节数组传递给本机方法做很多工作 - 它必须分配新内存,将托管字节数组复制到那,然后再次释放内存。
这意味着您发布的代码完全是胡说八道,因为虽然它确实修复了scratch_hash
数组,但它仍然没有使用该固定指针。
如果你只是偶尔调用一次方法并且字节数组相对较小,那么可以安全地忽略它。但是,如果您确实发现这会对您的应用程序造成不必要的压力,那么修复可能有所帮助 - 但您必须更改签名:
unsafe void get_checksum(uint cbData, out uint pcbData, byte *pbData);
然后你可以使用它:
fixed (byte *p = &scratch_hash[0])
sourceFile.get_checksum(c, out c, p);
所有这些说明,请注意修复托管对象可能会导致自己的问题(例如,如果您的对象位于堆顶部,它几乎会导致任何堆压缩的可能性)。应该谨慎地进行修复,并且只能进行极短的时间 - 唯一的另一个合理的选择是尽早分配对象并将它们保持在一起(例如,使用异步I / O时,需要一个固定的引用,通常需要很长时间当应用程序运行时 - 所以只需尽早分配缓冲区,你就会很好。)
另外,我仍然觉得签名有点疯狂。你能分享头文件的签名定义吗?