You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#调用C++ DLL时处理空数组与fixed关键字的问题

解决C#调用C++ DLL时空数组的指针传递问题

方案1:直接使用Fixed绑定整个数组(最简洁)

C#的fixed语句支持直接绑定整个数组,无需手动取&array[0]。当数组为null或长度为0时,绑定得到的指针会自动是null,正好匹配C++需要的空指针+长度0的逻辑。同时,多个数组可以放在同一个fixed块中,避免嵌套。

示例代码:

unsafe
{
    fixed (type1* thing1 = arrayOfThing1, type2* thing2 = arrayOfThing2)
    {
        // 传递数组长度,空数组或null时长度为0
        int len1 = arrayOfThing1?.Length ?? 0;
        int len2 = arrayOfThing2?.Length ?? 0;
        DllCallThatTakesLotsOfPointers(thing1, len1, thing2, len2);
    }
}

这个方案最直接,不需要额外封装,代码简洁易读,适合大多数场景。

方案2:封装泛型辅助类(适合大量参数的场景)

如果需要调用的DLL函数有非常多数组参数,或者需要统一处理数组固定逻辑,可以封装一个泛型辅助类,利用GCHandle手动管理数组的固定与释放:

public static unsafe class ArrayPinHelper
{
    // 获取固定后的指针,同时返回需要释放的GCHandle
    public static T* GetPinnedPointer<T>(T[] array, out GCHandle pinHandle) where T : unmanaged
    {
        pinHandle = default;
        if (array == null || array.Length == 0)
        {
            return null;
        }
        pinHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
        return (T*)pinHandle.AddrOfPinnedObject();
    }

    // 释放GCHandle
    public static void ReleasePin(ref GCHandle pinHandle)
    {
        if (pinHandle.IsAllocated)
        {
            pinHandle.Free();
            pinHandle = default;
        }
    }
}

调用示例:

unsafe
{
    GCHandle pin1 = default, pin2 = default;
    try
    {
        type1* ptr1 = ArrayPinHelper.GetPinnedPointer(arrayOfThing1, out pin1);
        type2* ptr2 = ArrayPinHelper.GetPinnedPointer(arrayOfThing2, out pin2);
        
        int len1 = arrayOfThing1?.Length ?? 0;
        int len2 = arrayOfThing2?.Length ?? 0;
        DllCallThatTakesLotsOfPointers(ptr1, len1, ptr2, len2);
    }
    finally
    {
        // 确保释放所有固定的句柄
        ArrayPinHelper.ReleasePin(ref pin1);
        ArrayPinHelper.ReleasePin(ref pin2);
    }
}

这个方案把数组固定的逻辑抽离,避免重复代码,适合需要频繁处理大量数组参数的场景。

方案3:利用Span(现代C#风格)

C# 7.3及以上支持fixed绑定Span<T>,而Span<T>天然支持空数组的处理,代码更符合现代C#的写法:

unsafe
{
    Span<type1> span1 = arrayOfThing1.AsSpan();
    Span<type2> span2 = arrayOfThing2.AsSpan();

    fixed (type1* ptr1 = span1, type2* ptr2 = span2)
    {
        DllCallThatTakesLotsOfPointers(ptr1, span1.Length, ptr2, span2.Length);
    }
}

Span<T>的Length属性会自动处理null数组(返回0),fixed绑定空Span时得到的指针也是null,逻辑清晰且代码简洁。


内容的提问来源于stack exchange,提问作者Craig Graham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 18:35:16