Usuwanie błędów i ostrzeżeń w niebezpiecznych konstrukcjach kodu

W tym artykule omówiono następującą diagnostykę kompilatora:

  • CS0193: Operator * lub -> musi być stosowany do wskaźnika
  • CS0196: Wskaźnik musi być indeksowany tylko przez jedną wartość
  • CS0208: Nie można pobrać adresu, pobrać rozmiaru lub zadeklarować wskaźnik do typu zarządzanego ('type')
  • CS0209: Typ lokalnej zmiennej zadeklarowanej w instrukcji fixed musi być typem wskaźnikowym
  • CS0210: Musisz podać inicjator w fixed lub using deklaracji instrukcji
  • CS0211: Nie można pobrać adresu danego wyrażenia
  • CS0212: Adres nieprzypisanego wyrażenia można pobrać tylko w ramach inicjatora instrukcji fixed
  • CS0213: Nie można użyć instrukcji fixed, aby uzyskać adres już ustalonego wyrażenia
  • CS0214: Wskaźniki i bufory o stałym rozmiarze mogą być używane tylko w niebezpiecznym kontekście
  • CS0227: Niebezpieczny kod może występować tylko w przypadku kompilowania za pomocą /unsafe polecenia
  • CS0233: "identyfikator" nie ma wstępnie zdefiniowanego rozmiaru, dlatego rozmiar może być używany tylko w niebezpiecznym kontekście
  • CS0242: Operacja, o której mowa, jest niezdefiniowana dla wskaźników typu void
  • CS0244: Instrukcje 'is' ani 'as' nie są poprawne dla typów wskaźnikowych
  • CS0254: Prawa strona przypisania stałej instrukcji może nie być wyrażeniem rzutowania
  • CS0459: Nie można pobrać adresu zmiennej lokalnej tylko do odczytu
  • CS0821: Nie można naprawić niejawnie wpisanych zmiennych lokalnych
  • CS1641: Pole buforu o stałym rozmiarze musi mieć specyfikator rozmiaru tablicy po nazwie pola
  • CS1642: Pola buforu o stałym rozmiarze mogą być tylko elementami członkowskimi struktur.
  • CS1656: Nie można przypisać do zmiennej , ponieważ jest to typ zmiennej tylko do odczytu.
  • CS1663: Typ buforu o stałym rozmiarze musi być jednym z następujących: bool, , byte, shortintlongcharsbyteushortuintulongfloatdouble lub
  • CS1665: Bufory o stałym rozmiarze muszą mieć długość większą niż zero
  • CS1666: Nie można używać buforów o stałym rozmiarze zawartych w nieustalonych wyrażeniach. Spróbuj użyć instrukcji fixed.
  • CS1708: Bufory o stałym rozmiarze mogą być dostępne tylko za pośrednictwem zmiennych lokalnych lub pól
  • CS1716: Nie używaj atrybutu "System.Runtime.CompilerServices.FixedBuffer". Zamiast tego użyj modyfikatora pola "fixed".
  • CS1919: Nie można użyć niebezpiecznego typu "nazwa typu" podczas tworzenia obiektu.
  • CS4004: Nie można await w niebezpiecznym kontekście
  • CS7092: Stały bufor może mieć tylko jeden wymiar.
  • CS8372: Nie używaj atrybutu "System.Runtime.CompilerServices.FixedBuffer" we właściwości
  • CS8812: Nie można przekonwertować grupy metod "method" na typ wskaźnika niebędący funkcją "type".
  • CS9049: Stałe pole nie może być polem ref.
  • CS9123: Operator "&" nie powinien być używany w parametrach ani zmiennych lokalnych w metodach asynchronicznych.
  • CS9360: Ta operacja może być używana tylko w niebezpiecznym kontekście
  • CS9361: stackalloc wyrażenie bez inicjatora wewnątrz SkipLocalsInit może być używane tylko w niebezpiecznym kontekście
  • CS9362: członek musi być używany w kontekście niebezpiecznym, ponieważ jest oznaczony jako "RequiresUnsafe" lub "extern"
  • CS9363: członek musi być używany w kontekście niebezpiecznym, ponieważ zawiera wskaźniki w podpisie
  • CS9364: Niebezpieczny członek „członek” nie może zastąpić bezpiecznego członka „członek”
  • CS9365: Niebezpieczny element 'member' nie może niejawnie implementować bezpiecznego elementu 'member'
  • CS9366: Niebezpieczny członek 'member' nie może implementować bezpiecznego członka 'member'
  • CS9367: RequiresUnsafeAttribute nie można zastosować do tego symbolu.
  • CS9368: RequiresUnsafeAttribute jest prawidłowy tylko zgodnie ze zaktualizowanymi regułami bezpieczeństwa pamięci.
  • CS9376: Niebezpieczny kontekst jest wymagany dla konstruktora 'constructor' oznaczonego jako 'RequiresUnsafe' lub 'extern', aby spełnić ograniczenie "new()" parametru typu "parametr typu" w typie ogólnym lub metodzie
  • CS9377: Modyfikator "unsafe" nie ma tutaj żadnego wpływu na obecne zasady bezpieczeństwa pamięci.

Operacje wskaźnika i wyłuszczanie

  • CS0193: Operator * lub -> musi zostać zastosowany do wskaźnika
  • CS0196: Wskaźnik musi być indeksowany tylko przez jedną wartość
  • CS0242: Operacja, o której mowa, jest niezdefiniowana dla wskaźników typu void

Aby prawidłowo używać operacji wskaźnika, postępuj zgodnie z regułami dotyczącymi operacji wyłuszczania, indeksowania i operacji arytmetycznych. Aby uzyskać więcej informacji, zobacz Typy wskaźników i wskaźniki funkcji.

  • Zastosuj operator * lub -> tylko do wskaźników danych (CS0193). Nie używaj tych operatorów z typami niewskaźnikowymi lub wskaźnikami funkcji. W przeciwieństwie do języków C/C++, w C# nie można używać wskaźników do funkcji bezpośrednio.
  • Wskaźniki indeksu z tylko jedną wartością (CS0196). Indeksowanie wielowymiarowe nie jest obsługiwane dla wskaźników.
  • Unikaj operacji, które są niezdefiniowane na wskaźnikach void (CS0242). Na przykład nie zwiększaj wskaźnika pustki, ponieważ kompilator nie zna rozmiaru wskazywanych danych.

Typy wskaźników i typy zarządzane

  • CS0208: Nie można pobrać adresu, pobrać rozmiaru lub zadeklarować wskaźnik do typu zarządzanego ('type')
  • CS0233: "identyfikator" nie ma wstępnie zdefiniowanego rozmiaru, dlatego rozmiar może być używany tylko w niebezpiecznym kontekście

Aby poprawnie pracować ze wskaźnikami i sizeof operatorem, użyj typów niezarządzanych i odpowiednich kontekstów. Aby uzyskać więcej informacji, zobacz Typy niezarządzane i sizeof operator.

  • Używaj wskaźników tylko z typami niezarządzanymi (CS0208). Nie należy pobierać adresu typów zarządzanych, określać ich rozmiaru ani deklarować do nich wskaźników. Typy zarządzane obejmują typy odwołań i struktury zawierające pola typu odwołania lub właściwości.
  • sizeof Użyj operatora w unsafe kontekście podczas pracy z typami, których rozmiar nie jest stałą czasu kompilacji (CS0233).

Naprawiono użycie wyrażenia

  • CS0209: Typ zmiennej lokalnej zadeklarowanej w instrukcji 'fixed' musi być typem wskaźnika
  • CS0210: Należy podać inicjator w deklaracji stałej lub using instrukcji
  • CS0211: Nie można pobrać adresu danego wyrażenia
  • CS0212: Adres niefiksowanego wyrażenia można pobrać tylko wewnątrz inicjatora stałej instrukcji
  • CS0213: Nie można użyć instrukcji 'fixed', aby uzyskać adres stałego już wyrażenia
  • CS0254: Prawa strona przypisania stałej instrukcji może nie być wyrażeniem rzutowania
  • CS0459: Nie można pobrać adresu zmiennej lokalnej tylko do odczytu
  • CS0821: Nie można naprawić niejawnie wpisanych zmiennych lokalnych
  • CS1656: Nie można przypisać do zmiennej , ponieważ jest to typ zmiennej tylko do odczytu.

Te błędy występują, gdy używasz instrukcjifixed niepoprawnie. Instrukcja fixed zapobiega przeniesieniu przenośnej zmiennej przez zbieracz odpadów i deklaruje wskaźnik do tej zmiennej. Aby uzyskać więcej informacji, zobacz Niebezpieczny kod i wskaźniki.

Aby poprawnie użyć instrukcji fixed :

  • Zadeklaruj zmienną jako typ wskaźnika (CS0209).
  • Podaj inicjator w deklaracji instrukcji fixed (CS0210).
  • Weź adres tylko prawidłowych wyrażeń: pola, zmienne lokalne i pośredni wskaźnik (CS0211). Nie należy przyjmować adresu obliczonych wyrażeń, takich jak suma dwóch zmiennych.
  • Użyj operatora address-of w wyrażeniach niefiksowanych tylko w inicjatorze fixed instrukcji (CS0212).
  • Nie używaj instrukcji fixed w wyrażeniach już stałych (CS0213). Zmienne lokalne i parametry w metodzie unsafe są już przypisane na stosie.
  • Nie używaj wyrażeń rzutowania po prawej stronie fixed przypisania instrukcji (CS0254).
  • Nie należy przyjmować adresu zmiennych lokalnych oznaczonych jako 'tylko do odczytu' (CS0459). Zmienne w foreach pętlach oraz using i fixed instrukcjach są tylko do odczytu. Ten błąd nie jest już generowany przez bieżące wersje kompilatora.
  • Użyj typów jawnych zamiast var w instrukcjach fixed (CS0821).
  • Nie przypisuj zmiennych w kontekstach przeznaczonych wyłącznie do odczytu, takich jak foreach pętle, using lub fixed instrukcje (CS1656).

Wymagania dotyczące niebezpiecznego kontekstu

  • CS0214: Wskaźniki i bufory o stałym rozmiarze mogą być używane tylko w niezabezpieczonym kontekście
  • CS0227: Niebezpieczny kod może występować tylko w przypadku kompilowania z /niebezpiecznym
  • CS0244: Żaden z elementów "is" ani "as" nie jest dozwolony dla typów wskaźników
  • CS1919: Nie można użyć niebezpiecznego typu "nazwa typu" podczas tworzenia obiektu
  • CS4004: Nie można await w kontekście niebezpiecznym
  • CS9123: Operator "&" nie powinien być używany w parametrach ani zmiennych lokalnych w metodach asynchronicznych
  • CS9360: Ta operacja może być używana tylko w niebezpiecznym kontekście
  • CS9361: stackalloc wyrażenie bez inicjatora wewnątrz SkipLocalsInit może być używane tylko w niebezpiecznym kontekście
  • CS9362: element członkowski musi być używany w niebezpiecznym kontekście, ponieważ jest oznaczony jako "RequiresUnsafe" lub "extern"
  • CS9363: 'członek' musi być używany w niebezpiecznym kontekście, ponieważ zawiera wskaźniki w swojej sygnaturze
  • CS9376: Niebezpieczny kontekst jest wymagany dla konstruktora oznaczonego jako "RequiresUnsafe" lub "extern", aby spełnić ograniczenie "new()" parametru typu w typie ogólnym lub metodzie

Ta diagnostyka występuje, gdy używasz niebezpiecznych konstrukcji kodu bez wymaganego unsafe kontekstu lub podczas próby wykonywania operacji, które nie są dozwolone z niebezpiecznymi typami. Aby uzyskać więcej informacji, zobacz Niebezpieczny kod i wskaźniki oraz unsafe słowo kluczowe.

  • Oznacz metody, typy lub bloki kodu korzystające ze wskaźników lub o stałym rozmiarze ze słowem kluczowym unsafe (CS0214). Kompilator wymaga jawnego niebezpiecznego kontekstu dla dowolnego kodu, który działa z typami wskaźnika lub polami buforu o stałym rozmiarze.
  • Włącz opcję kompilatora AllowUnsafeBlocks w ustawieniach projektu (CS0227). Bez tej opcji kompilator odrzuca wszystkie unsafe bloki, nawet jeśli kod jest w inny sposób poprawny.
  • Nie używaj operatorów is lub as z typami wskaźników (CS0244). Te operatory testowania typów nie są prawidłowe dla wskaźników, ponieważ wskaźniki nie uczestniczą w hierarchii typów.
  • Nie używaj new operatora do tworzenia wystąpień typu wskaźnika (CS1919). Aby utworzyć obiekty w niezarządzanej pamięci, użyj międzyoperacyjności, aby wywołać metody natywne zwracające wskaźniki.
  • Zachowaj niebezpieczny kod niezależnie od kodu asynchronicznego (CS4004). Kompilator nie zezwala na await wyrażenia wewnątrz unsafe bloku, ponieważ środowisko uruchomieniowe nie może zagwarantować ważności wskaźnika w punktach zawieszenia. Utwórz oddzielne metody dla niebezpiecznych operacji i wywołaj je z metod asynchronicznych.
  • Nie używaj operatora address-of (&) dla parametrów ani zmiennych lokalnych w metodach asynchronicznych (CS9123). Zmienna może nie istnieć na stosie, gdy operacja asynchroniczna zostanie wznowiona po wystąpieniu punktu zawieszenia.
  • Oznacz operacje obejmujące niebezpieczne konstrukcje (takie jak dereferencja wskaźnika, operator pobierania adresu lub sizeof na typach niezarządzanych) za pomocą słowa kluczowego unsafe (CS9360). W ramach zaktualizowanych reguł bezpieczeństwa pamięci w języku C# 15 kompilator identyfikuje poszczególne operacje, które wymagają niebezpiecznego kontekstu.
  • Użyj słowa kluczowego unsafe dla stackalloc wyrażeń bez inicjatorów, gdy SkipLocalsInit atrybut jest stosowany (CS9361). Bez inicjalizatora zarezerwowana pamięć na stosie zawiera niezainicjalizowane dane, co stanowi niebezpieczną operację.
  • Użyj unsafe kontekstu podczas wywoływania składników oznaczonych jako RequiresUnsafe lub extern (CS9362) lub składników ze wskaźnikami w ich podpisach (CS9363). Kompilator języka C# 15 śledzi niebezpieczne użycie członków w miejscu wywołania, a nie tylko w deklaracji.
  • unsafe Użyj kontekstu, gdy new() ograniczenie wymaga wywołania konstruktora oznaczonego znakiem RequiresUnsafe lub extern (CS9376). Instancja ogólna wywołuje konstruktor niejawnie, więc kontekst wywołujący musi być niesafe.

Niebezpieczne umowy dotyczące bezpieczeństwa członków

  • CS9364: Niebezpieczny członek 'member' nie może zastąpić bezpiecznego członka 'member'
  • CS9365: Niebezpieczny członek 'member' nie może niejawnie zaimplementować bezpiecznego członka 'member'
  • CS9366: Niebezpieczny element członkowski "członek" nie może zaimplementować bezpiecznego elementu członkowskiego "członek"
  • CS9367: RequiresUnsafeAttribute nie można zastosować do tego symbolu.
  • CS9368: RequiresUnsafeAttribute jest prawidłowy tylko zgodnie ze zaktualizowanymi regułami bezpieczeństwa pamięci.
  • CS9377: Modyfikator "unsafe" nie ma tutaj żadnego wpływu na obecne zasady bezpieczeństwa pamięci.

Ta diagnostyka wymusza reguły kontraktu bezpieczeństwa języka C# 15 dla członków oznaczonych jako niebezpieczne. Kompilator zapewnia, że niebezpieczne elementy członkowskie nie naruszają oczekiwań bezpieczeństwa ustanowionych przez klasy bazowe i interfejsy. Aby uzyskać więcej informacji, zobacz Niebezpieczny kod i wskaźniki oraz unsafe słowo kluczowe.

  • Nie przesłaniaj bezpiecznego elementu podstawowego członkiem niebezpiecznym (CS9364). Przesłonięcie musi zachować kontrakt bezpieczeństwa elementu bazowego. Jeśli element podstawowy jest bezpieczny, nadpisanie musi być również bezpieczne. Usuń modyfikator unsafe lub RequiresUnsafeAttribute z zastępującego członka lub oznacz podstawowy członek jako niebezpieczny.
  • Nie implementuj implicitnie bezpiecznego elementu członkowskiego interfejsu za pomocą niebezpiecznego elementu członkowskiego (CS9365). Gdy typ niejawnie implementuje element członkowski interfejsu, wywołujące za pośrednictwem interfejsu oczekują bezpiecznej operacji. Usuń niebezpieczne oznaczenie ze składnika implementacji lub użyj implementacji interfejsu jawnego.
  • Nie implementuj jawnie bezpiecznego członka interfejsu przy użyciu niebezpiecznego członka (CS9366). Nawet w przypadku jawnej implementacji należy zachować kontrakt bezpieczeństwa elementu członkowskiego interfejsu.
  • Zastosuj RequiresUnsafeAttribute tylko do obsługiwanych typów symboli (CS9367). Ten atrybut można zastosować do metod, właściwości, zdarzeń, konstruktorów i typów, ale nie wszystkie rodzaje symboli go obsługują.
  • Włącz zaktualizowane reguły bezpieczeństwa pamięci, aby używać RequiresUnsafeAttribute (CS9368). Ten atrybut jest częścią ulepszonego modelu bezpieczeństwa pamięci w języku C# 15 i nie jest rozpoznawany zgodnie ze starszymi regułami. Upewnij się, że projekt jest przeznaczony dla wersji językowej obsługującej zaktualizowane reguły.
  • unsafe Usuń modyfikator, gdy nie ma żadnego efektu (CS9377). Zgodnie z bieżącymi regułami bezpieczeństwa pamięci niektóre konteksty nie wymagają ani nie korzystają z unsafe modyfikatora. Kompilator ostrzega, gdy modyfikator jest bez znaczenia, dzięki czemu można wyczyścić niepotrzebne adnotacje.

bufory o stałym rozmiarze

  • CS1641: Pole buforu o stałym rozmiarze musi mieć specyfikator rozmiaru tablicy po nazwie pola
  • CS1642: Pola buforu o stałym rozmiarze mogą być tylko elementami członkowskimi struktur
  • CS1663: Typ buforu o stałym rozmiarze musi być jednym z następujących: bool, , byte, shortintlongcharsbyteushortuintulongfloatdouble lub
  • CS1665: Bufory o stałym rozmiarze muszą mieć długość większą niż zero
  • CS1666: Nie można używać buforów o stałym rozmiarze znajdujących się w niezafiksowanych wyrażeniach. Spróbuj użyć instrukcji fixed
  • CS1708: Bufory o stałym rozmiarze mogą być dostępne tylko poprzez zmienne lokalne lub pola
  • CS1716: Nie używaj atrybutu "System.Runtime.CompilerServices.FixedBuffer". Zamiast tego użyj modyfikatora pola "fixed"
  • CS7092: Stały bufor może mieć tylko jeden wymiar.
  • CS8372: Nie używaj atrybutu "System.Runtime.CompilerServices.FixedBuffer" we właściwości
  • CS9049: Stałe pole nie może być polem ref

Te błędy występują podczas pracy z buforami o stałym rozmiarze. Bufory o stałym rozmiarze to tablice osadzone bezpośrednio w strukturach i są używane głównie w scenariuszach interopu. Aby uzyskać więcej informacji, zobacz bufory o stałym rozmiarze.

Aby poprawnie zadeklarować bufory o stałym rozmiarze i używać ich:

  • Określ rozmiar tablicy po nazwie pola przy użyciu dodatniej stałej całkowitej (CS1641, CS1665).
  • Zadeklaruj bufory o stałym rozmiarze tylko w strukturach, a nie w klasach (CS1642). Jeśli potrzebujesz pola w klasie, użyj tablicy regularnej.
  • Użyj jednego z obsługiwanych typów elementów: bool, , byte, shortintlongcharsbyteushortuintulongfloatlub double (CS1663).
  • Użyj instrukcji fixed aby przypiąć zawierającą strukturę przed uzyskaniem dostępu do buforu (CS1666).
  • Bufory o stałym rozmiarze używaj tylko za pośrednictwem zmiennych lokalnych lub pól, a nie za pośrednictwem wyrażeń pośrednich (CS1708).
  • fixed Użyj modyfikatora pól zamiast atrybutu System.Runtime.CompilerServices.FixedBuffer (CS1716). Nie stosuj tego atrybutu do właściwości (CS8372).
  • Zadeklaruj stałe bufory tylko z jednym wymiarem (CS7092). Wielowymiarowe stałe bufory nie są obsługiwane.
  • Nie deklaruj buforów o stałym rozmiarze jako pól (ref). o stałym rozmiarze muszą być polami wartości.

Wskaźniki funkcji

  • CS8812: Nie można przekonwertować grupy metod „method” na typ wskaźnika innego niż funkcja „type”.

Aby uzyskać wskaźnik funkcji, użyj operatora address-of z jawnym rzutowaniem na typ wskaźnika funkcji. Nie używaj operatora &address-of, aby przypisać grupy metod do void* lub innych typów wskaźników innych niż funkcja. Aby uzyskać więcej informacji, zobacz Wskaźniki funkcji.