Czy rzeczywiście używasz wskaźników w C #? [Zamknięte]

19

Jaka jest sytuacja podczas kodowania w C #, gdzie używanie wskaźników jest dobrą lub konieczną opcją? Mówię o niebezpiecznych wskazówkach.

Gulszan
źródło
8
Ach, człowieku, widziałem pytanie i byłem szczęśliwy, ponieważ mogłem wyjaśnić, że w języku C # używasz wskaźników cały czas, ale musisz iść i zepsuć to, mówiąc wyraźnie niebezpieczne słowo kluczowe. Cholera! :)
Tony

Odpowiedzi:

25

Od twórcy samego C #:

Użycie wskaźników jest rzadko wymagane w języku C #, ale są pewne sytuacje, które ich wymagają. Jako przykłady użycie niebezpiecznego kontekstu w celu umożliwienia korzystania ze wskaźników jest uzasadnione w następujących przypadkach:

  • Radzenie sobie z istniejącymi strukturami na dysku
  • Zaawansowane scenariusze COM lub Platform Invoke, które obejmują struktury ze wskaźnikami
  • Kod krytyczny dla wydajności

Używanie niebezpiecznego kontekstu w innych sytuacjach jest odradzane.

W szczególności nie należy używać niebezpiecznego kontekstu do próby napisania kodu C w języku C #.

Uwaga: „Nie można zweryfikować, czy kod napisany przy użyciu niebezpiecznego kontekstu jest bezpieczny, dlatego zostanie wykonany tylko wtedy, gdy kod będzie w pełni zaufany. Innymi słowy, niebezpiecznego kodu nie można wykonać w niezaufanym środowisku. Na przykład nie można uruchomić niebezpiecznego kodu kod bezpośrednio z Internetu ”.

Możesz przejść przez to w celach informacyjnych

ykombinator
źródło
„niebezpiecznego kodu nie można wykonać w niezaufanym środowisku”. Miałeś na myśli „zaufany”?
Don Larynx
18

tak, istnieją rzeczywiste zastosowania, gdy wydajność jest krytyczna, a operacje są na niskim poziomie

na przykład, potrzebowałem tylko raz użyć wskaźników w C # do porównania obrazu. Wykorzystanie GetPixel na parze obrazów 1024x1024x32 zajęło 2 minuty na wykonanie porównania (dopasowanie ścisłe). Przypięcie pamięci obrazu i użycie wskaźników zajęło mniej niż 1 sekundę (oczywiście na tej samej maszynie).

Steven A. Lowe
źródło
2
Użyłem do tego LockBits ... ( msdn.microsoft.com/en-us/library/… )
konfigurator
1
@configurator: to był .net 2, LockBits nie istniał
Steven A. Lowe
2
Pewnie, że tak, istnieje od 1.0 ...
konfigurator
@configurator: mój błąd, pomyliłem się podczas przeglądania dokumentacji MSDN (kiedy zmieniłem na .net 2 na liście rozwijanej, przeszedłem na zupełnie inną stronę, która nie wspomniała o blokadach). Tak, tak przypinasz pamięć obrazu.
Steven A. Lowe,
6

Musisz pamiętać, że projektanci Microsoft to inteligentni ludzie i wszystko, co dodają do C #, ma co najmniej 1 przypadek użycia. Projekt FParsec używa niebezpiecznego kodu, aby wydobyć każdą ostatnią kroplę wydajności, jaką potrafi C #. Zwróć uwagę na użycie fixedi stackalloc.

private char* ReadCharsFromStream(char* buffer, int maxCount, out string overhangChars) {
    Debug.Assert(maxCount >= 0);
    fixed (byte* byteBuffer = ByteBuffer) {
        overhangChars = null;
        try {
            while (maxCount >= MaxCharCountForOneByte) {// if maxCount < MaxCharCountForOneByte, Convert could throw
                int nBytesInByteBuffer = FillByteBuffer();
                bool flush = nBytesInByteBuffer == 0;
                int bytesUsed, charsUsed; bool completed = false;
                Decoder.Convert(byteBuffer + ByteBufferIndex, nBytesInByteBuffer,
                                buffer, maxCount, flush,
                                out bytesUsed, out charsUsed, out completed);
                ByteBufferIndex += bytesUsed; // GetChars consumed bytesUsed bytes from the byte buffer
                buffer += charsUsed;
                maxCount -= charsUsed;
                if (flush && completed) return buffer;
            }
            if (maxCount == 0) return buffer;

            char* cs = stackalloc char[MaxCharCountForOneByte];
            for (;;) {
                int nBytesInByteBuffer = FillByteBuffer();
                bool flush = nBytesInByteBuffer == 0;
                int bytesUsed, charsUsed; bool completed;
                Decoder.Convert(byteBuffer + ByteBufferIndex, nBytesInByteBuffer,
                                cs, MaxCharCountForOneByte, flush,
                                out bytesUsed, out charsUsed, out completed);
                ByteBufferIndex += bytesUsed;
                if (charsUsed > 0) {
                    int i = 0;
                    do {
                        *(buffer++) = cs[i++];
                        if (--maxCount == 0) {
                            if (i < charsUsed) overhangChars = new string(cs, i, charsUsed - i);
                            return buffer;
                        }
                    } while (i < charsUsed);
                }
                if (flush && completed) return buffer;
            }
        } catch (DecoderFallbackException e) {
            e.Data.Add("Stream.Position", ByteIndex + e.Index);
            throw;
        }
    }
}
ChaosPandion
źródło
1
Powiedziałbym, że programiści (w Microsoft lub innych firmach) byliby idiotami, gdyby umieścili jakąś funkcję, ponieważ ma ona 1 przypadek użycia. Funkcja powinna mieć znacznie więcej niż 1 przypadki użycia; w przeciwnym razie jest to wzdęcie.
Lie Ryan,
4
Raymond Chen często powtarzał, że funkcje w Microsoft zaczynają się od -100 „punktów”. Aby funkcja mogła zostać zaimplementowana, „musi mieć znaczący pozytywny wpływ netto na cały pakiet, aby mogła zostać wprowadzona”. Oto post na blogu ericgu o tym c.2004: blogs.msdn.com/b/ericgu/archive/2004/01/12/57985.aspx
Jesse Buchanan
Jestem prawie pewien, że niektóre operacje na Stringach używają niebezpiecznego kodu. FParsec mógł więc nie być priorytetem.
Arturo Torres Sánchez
4

Kiedyś musiałem używać wskaźników (w niebezpiecznym kontekście) w aplikacji systemu Windows opartej na języku C #, która działałaby jako interfejs zestawu słuchawkowego. Ta aplikacja to interfejs użytkownika, który pozwala agentom (w call center) kontrolować ustawienia słuchawek. Ta aplikacja działa jako alternatywa dla panelu sterowania podanego przez producenta zestawu słuchawkowego. Ich zdolność do sterowania zestawami słuchawkowymi była zatem ograniczona w porównaniu z dostępnymi opcjami. Musiałem użyć wskaźników, ponieważ musiałem użyć interfejsu API (dll Visual C ++) dostarczonego przez producenta zestawu słuchawkowego za pomocą P / Invoke.

k25
źródło