سؤال

لدي صفيف خشن الذي أحتاج إلى نقله إلى الطريقة الخارجية.

[DllImport(...)]
private static extern int NativeMethod(IntPtr[] ptrArray);

...

fixed (ulong* ptr = array[0])
{
    for (int i = 0; i < array.Length; i++)
    {
        fixed (ulong* p = &array[i][0])
        {
            ptrArray[i] = new IntPtr(p);
        }
    }

    NativeMethod(ptrArray);
}

المشكلة هي أن PTR غير مستخدم ويتم إزالته بسبب التجميع. من البيان الثابت وفقًا له تتم إزالته أيضًا. لذلك يتم نقل الصفيف بواسطة GC بهذه الطريقة التي تصبح فيها عناصر ptrarray غير صالحة.

ما هي أفضل طريقة لتمرير المصفوفات المسننة كصفائف أحادية الأبعاد من المؤشرات إلى الأساليب الأصلية؟

تحديث:

هنا هو رمز C ++ لـ Nativemethod:

NativeClass::NativeMethod(const int* array)
هل كانت مفيدة؟

المحلول

مشكلتك هي حقيقة أنك تحتاج إلى إصلاح صفيف لأن هذا هو الشخص الذي تستخدمه. يمكنك تثبيت المصفوفة حتى لا يقوم GC بجمعه:

 GCHandle h = GCHandle.Alloc(array, GCHandleType.Pinned);

تحديث

كما أشرت بشكل صحيح ، يحتاج كل صفيف داخل الصفيف إلى تثبيت أيضًا.

نصائح أخرى

لقد تمكنت من تمرير مجموعة C# jagged إلى C ++ عبر طريقة Pinvoke الخارجية دون استخدام رمز C# غير آمن كما في عينة الكود أدناه. لكن لا يزال لديّ مخاوفي بشأن GC في وضع غير Debug مما تسبب في تأثير جانبي غير مرغوب فيه. إليك قطعة رمز الاختبار (التي تعمل في وضع التصحيح):

[Test, Ignore]
public void Test_JaggedArrayPInvoke()
{
    var jaggedArray = new int[3][];
    jaggedArray[0] = new int[1] { 9 };
    jaggedArray[1] = new int[4] { 1, 2, 3, 8 };
    jaggedArray[2] = new int[2] { 1, 2 };

    //GCHandle mainHandle = GCHandle.Alloc(jaggedArray, GCHandleType.Pinned);   //This does not work

    var pinnedHandles = new GCHandle[3];                    
    var jaggedArrayPtrs = new IntPtr[3];
    for (int i = 0; i < 3; i++)
    {
        pinnedHandles[i] = GCHandle.Alloc(jaggedArray[i], GCHandleType.Pinned);
        jaggedArrayPtrs[i] = pinnedHandles[i].AddrOfPinnedObject();
    }

    var result = JaggedArrayPInvoke_TEST(jaggedArrayPtrs);

    Console.WriteLine(result);  //returns 8 as it should.

    //mainHandle.Free();
    for (int i = 0; i < 3; i++)
    {
        pinnedHandles[i].Free();
    }
}

//The C++ test method:

extern "C" __declspec(dllexport) int __stdcall JaggedArrayPInvoke_TEST(int** jaggedArray);
__declspec(dllexport) int __stdcall JaggedArrayPInvoke_TEST(int** jaggedArray) 
{ 
   return jaggedArray[1][3];
}

إذا كنت أرغب في إلغاء التغلب على جزء MainHandle ، أحصل على استثناء من الوسيطة "يحتوي الكائن على بيانات غير متناظرة أو غير قابلة للتشكيل". فهل من الممكن تثبيت jaggedarray وهل هو مطلوب حقًا؟ (أذكر بشكل غامض أن GC في وضع الإصدار قد يتذكر الذاكرة بالفعل ضمن الطرق إذا لم يتم استخدامها بعد الآن.) على الرغم من أن تحويل JaggedArray إلى متغير حقل الفصل بدلاً من ذلك سيجعله آمنًا من منظور GC.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top