2009-07-31 10 views
32

W odpowiedzi na pytanie zadane another question pojawił się komentarz wskazujący, że metoda Array.Copy architektury .NET używa niezarządzanego kodu. Poszedłem kopanie z Reflector i znalazł podpis jednego z Array.Copy metody przeciążeń jest zdefiniowany jako tak:C# wewnętrzny adres statyczny z atrybutem InternalCall - wewnętrzny czy zewnętrzny?

[MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)] 
internal static extern void Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length, bool reliable); 

Po patrząc na to, jestem nieco zdezorientowany. Źródłem mojego zamieszania jest modyfikator extern co oznacza (MSDN link):

extern modyfikator służy do deklarowania metodę, która jest realizowany zewnętrznie.

Jednak deklaracja metoda jest również ozdobiona atrybutu MethodImplOptions.InternalCall, co wskazuje (MSDN link):

Określa połączenie wewnętrzne. Wywołanie wewnętrzne jest wywołaniem metody, która jest implementowana we wspólnym środowisku wykonawczym języka .

Czy ktoś może wyjaśnić tę pozornie widoczną sprzeczność?

Odpowiedz

46

Po prostu skomentowałam na leppie's post, ale robiło się trochę długo.

Obecnie pracuję nad eksperymentalną implementacją interfejsu CLI. Istnieje wiele przypadków, w których publicznie dostępna metoda (lub własność) nie może zostać zaimplementowana bez wiedzy o sposobie wewnętrznego wdrożenia maszyny wirtualnej. Jednym z przykładów jest OffsetToStringData, który wymaga znajomości sposobu przydzielania łańcuchów przez menedżera pamięci.

W przypadkach takich jak ten, w których nie ma kodu C# do wyrażenia metody, można traktować każde wywołanie metody w specjalny sposób wewnętrzny do procesu JIT. Jako przykład tutaj, zamieniając kod bajtowy call na ldc.i4 (stała liczba całkowita obciążenia) przed przekazaniem go do natywnego generatora kodu. Flaga InternalCall oznacza "Ciało tej metody jest traktowane w specjalny sposób przez sam system wykonawczy." Może, ale nie musi być to faktyczna implementacja - w wielu przypadkach w moim kodzie wywołanie jest traktowane przez JIT jako intrinsic.

Istnieją również inne przypadki, w których JIT może dysponować specjalnymi informacjami, które umożliwiają dużą optymalizację metody. Jednym z przykładów jest metoda Math, w której nawet te can be implemented in C#, określając InternalCall, aby uczynić je skutecznie wewnętrznymi, ma znaczące zalety w zakresie wydajności.

W języku C# metoda musi mieć treść, chyba że jest to abstract lub extern. extern oznacza ogólne "Możesz wywołać tę metodę z kodu C#, ale jej treść jest faktycznie zdefiniowana gdzie indziej.". Gdy JIT osiągnie połączenie z metodą extern, wyszukuje gdzie znaleźć ciało i zachowuje się w różny sposób w zależności od wyniku.

  • Atrybut DllImport instruuje JIT dokonać P/Invoke niedopałek zadzwonić natywnej implementacji kodu.
  • Flaga instruuje JIT, aby traktował wywołanie w sposób samoczynny.
  • (Istnieje kilka innych, ale nie mam przykłady od szczytu głowy do ich stosowania.)
15

InternalCall oznacza zapewnione przez ramy.

extern mówi, że nie podajesz kodu.

extern może być stosowany w 2 sytuacjach ogólnych, jak wyżej, lub przy użyciu p/invoke.

Za pomocą p/invoke po prostu podajesz metodę, w której chcesz uzyskać implementację.

+0

@leppie - Chciałbym zaznaczyć obie swoje i odpowiedzi 280Z28 jako przyjęte od ciebie” Oba poprawne. Uważam jednak, że odpowiedź 280Z28 nieco bardziej wyjaśnia i pomogła mi lepiej zrozumieć, dziękuję za wasz wysiłek. – CraigTP

+0

Nie ma problemu, mam już dość punktów, dam mu jeszcze trochę :) – leppie

Powiązane problemy