2013-01-16 8 views
6

Załóżmy, że jest wbudowana funkcja z interfejsem czystej C, jak na przykładzie jednego eksportowane z natywnego DLL:Czy atrybuty P/Invoke [In, Out] są opcjonalne do porządkowania tablic?

// NativeDll.cpp 

extern "C" void __stdcall FillArray(
    int fillValue, 
    int count, 
    int* data) 
{ 
    // Assume parameters are OK... 

    // Fill the array 
    for (int i = 0; i < count; i++) 
    { 
     data[i] = fillValue; 
    } 
} 

Poniżej P/wywołać współpracuje (testowane z VS2010 SP1)

[DllImport("NativeDll.dll", CallingConvention=CallingConvention.StdCall)] 
public static extern void FillArray(
    int fillValue, 
    int count, 
    [In, Out] int[] data 
); 

jak to P/wywołać, tak samo jak wyżej, lecz bez [In, Out] atrybutów:

[DllImport("NativeDll.dll", CallingConvention=CallingConvention.StdCall)] 
public static extern void FillArray(
    int fillValue, 
    int count, 
    int[] data 
); 

Czy są zatem dostępne atrybuty [In, Out]jako opcjonalne dla tablic marszałkowskich? Jaki jest ich cel, jeśli taki istnieje? Czy można je pominąć w naszych deklaracjach P/Invoke?

Odpowiedz

16

Nie, nie są one dokładnie opcjonalne. Po prostu działa przez przypadek. Jest to jednak bardzo często wypadek. Działa, ponieważ tablica nie jest w rzeczywistości marnowana. Pinvoke marshaller widzi, że tablica C# jest już kompatybilna z macierzystą tablicą, więc pomija krok, aby utworzyć jego kopię. Po prostu przypina tablicę i przekazuje wskaźnik do natywnego kodu.

Jest to oczywiście bardzo wydajne i nieuchronnie uzyskasz wyniki, ponieważ kod natywny bezpośrednio zapisuje elementy tablicy. Zatem nie ma znaczenia atrybut [In] ani [Out].

To staje się znacznie mroczniejsze, jeśli typ elementu tablicy nie jest tak prosty. Nie jest łatwo zidentyfikować typ elementu, który jest strukturą lub typem klasy, który nie jest blittable lub którego układ nie pasuje po marshmalingu, więc pinvoke marshaller ma, aby utworzyć kopię tablicy. Zwłaszcza niezgodność układu może być trudna do zidentyfikowania, ponieważ zarządzany układ jest niemożliwy do wykrycia. I może się zmieniać w zależności od używanego jittera. Może działać na x86, ale nie na przykład na x64, całkiem nieprzyjemny, gdy wybrany jest AnyCPU. Wprowadzenie do kopiowania zmodyfikowanej kopii z powrotem do tablicy C# wymaga wymagają [Out].

Nie jestem pewien, co doradzić, poza tym, że nikt nigdy nie został zwolniony z tego powodu, że wyraził się jasno w swoich deklaracjach. Być może zawsze powinieneś być wyraźny, gdy typ elementu tablicy nie jest prosty, więc nigdy nie będziesz miał wypadku.

+1

Ugh ... Spędziłem tyle godzin z mojego życia, rozwiązując problemy między X86/x64/"Any CPU" ... – JerKimball