我有一些unsafe
C#代码无法更改,并公开了这样的方法:
static unsafe void Foo(
byte* a, int aLength,
byte* b, int bLength,
byte* c, int cLength,
byte* d, int dLength,
byte* e, int eLength);
我正在调用这样的方法:
static void Bar(
byte[] a, int aOffset, int aLength,
byte[] b, int bOffset, int bLength,
byte[] c, int cOffset, int cLength,
byte[] d, int dOffset, int dLength,
byte[] e, int eOffset, int eLength)
{
fixed (byte* a_ = &a[aOffset])
fixed (byte* b_ = &b[bOffset])
fixed (byte* c_ = &c[cOffset])
fixed (byte* d_ = &d[dOffset])
fixed (byte* e_ = &e[eOffset])
{
Foo(a_, aLength,
b_, bLength,
c_, cLength,
d_, dLength,
e_, eLength);
}
}
(为简洁起见,省略了参数验证。)
除非其中一个字节数组的长度为零,否则这种方法很有效。在这种情况下,我得到一个IndexOutOfRangeException。
索引超出了数组的范围。
如何防止异常,最好不要编写大量样板代码而不从fixed
转换为其他内容?
不安全的方法不读取或写入长度为零的参数。
答案 0 :(得分:2)
您无法访问数组中为空的任何元素,因此请使用包含您可以访问的元素的虚拟数组替换任何空数组:
if (aLength == 0) a = new int[1];
if (bLength == 0) b = new int[1];
if (cLength == 0) c = new int[1];
if (dLength == 0) d = new int[1];
if (eLength == 0) e = new int[1];
答案 1 :(得分:0)
是
static void Bar( ... )
{
byte[] dummy = new byte[1];
fixed (byte* a_ = a.Lenght>0 ? &a[aOffset] : &dummy[0])
...
}
太笨重了?
修改强>
仅出于历史原因离开上述地方,?
运营商无法工作。
因此,您需要不使用fixed
关键字,并执行类似
public unsafe struct UnsafePointerStruct
{
public GCHandle gch;
public byte* addr;
}
static unsafe UnsafePointerStruct GetUnsafePointer(Array a, int ai)
{
UnsafePointerStruct ups=new UnsafePointerStruct();
ups.gch=GCHandle.Alloc(a,GCHandleType.Pinned);
if (a.Length<=ai) ups.addr=(byte*)IntPtr.Zero;
ups.addr=(byte*)Marshal.UnsafeAddrOfPinnedArrayElement(a,ai);
return ups;
}
static unsafe void Bar(
byte[] a, int aOffset, int aLength,
byte[] b, int bOffset, int bLength,
byte[] c, int cOffset, int cLength,
byte[] d, int dOffset, int dLength,
byte[] e, int eOffset, int eLength)
{
UnsafePointerStruct upsa=GetUnsafePointer(a,aOffset);
UnsafePointerStruct upsb=GetUnsafePointer(b,bOffset);
UnsafePointerStruct upsc=GetUnsafePointer(c,cOffset);
UnsafePointerStruct upsd=GetUnsafePointer(d,dOffset);
UnsafePointerStruct upse=GetUnsafePointer(e,eOffset);
Foo(upsa.addr, aLength,
upsb.addr, bLength,
upsc.addr, cLength,
upsd.addr, dLength,
upse.addr, eLength);
upsa.gch.Free();
upsb.gch.Free();
upsc.gch.Free();
upsd.gch.Free();
upse.gch.Free();
}
答案 2 :(得分:0)
由于它不读取或写入长度为零的数组,因此可以更改
fixed (byte* a_ = &a[aOffset])
fixed (byte* b_ = &b[bOffset])
fixed (byte* c_ = &c[cOffset])
fixed (byte* d_ = &d[dOffset])
fixed (byte* e_ = &e[eOffset])
到
fixed (byte* a_ = (a.Length == 0 ? (byte*)IntPtr.Zero : &a[aOffset]))
fixed (byte* b_ = (b.Length == 0 ? (byte*)IntPtr.Zero : &b[aOffset]))
fixed (byte* c_ = (c.Length == 0 ? (byte*)IntPtr.Zero : &c[aOffset]))
fixed (byte* d_ = (d.Length == 0 ? (byte*)IntPtr.Zero : &d[aOffset]))
fixed (byte* e_ = (e.Length == 0 ? (byte*)IntPtr.Zero : &e[aOffset]))
但是如果你这样做然后尝试读取或写入其中一个空数组,你将得到一个nullpointer异常。