1

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);
    }
}

(簡潔にするため、引数の検証は省略されています。)

これは、バイト配列の1つがゼロの長さでない限りうまく機能します。この場合、IndexOutOfRangeExceptionが発生します。

インデックスが配列の範囲外だった。

できれば大量の定型コードを記述せずに、またfixed他のものに切り替えることなく、例外を防ぐにはどうすればよいですか?

安全でないメソッドは、長さがゼロの引数からの読み取りまたは引数への書き込みを行いません。

4

3 に答える 3

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];
于 2012-06-02T23:36:35.187 に答える
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();
}
于 2012-06-02T23:38:20.380 に答える
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]))

ただし、これを実行してから、空の配列の1つに対して読み取りまたは書き込みを行おうとすると、nullpointer例外が発生します。

于 2012-06-02T23:41:50.667 に答える