Jaka jest sytuacja podczas kodowania w C #, gdzie używanie wskaźników jest dobrą lub konieczną opcją? Mówię o niebezpiecznych wskazówkach.
Jaka jest sytuacja podczas kodowania w C #, gdzie używanie wskaźników jest dobrą lub konieczną opcją? Mówię o niebezpiecznych wskazówkach.
Odpowiedzi:
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
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).
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 fixed
i 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;
}
}
}
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.