CA2020: Förhindra beteendeförändring som orsakas av inbyggda operatorer av IntPtr/UIntPtr
Property | Värde |
---|---|
Regel-ID | CA2020 |
Title | Förhindra beteendeförändringar som orsakas av inbyggda operatorer av IntPtr/UIntPtr |
Kategori | Tillförlitlighet |
Korrigeringen är icke-bakåtkompatibel | Icke-icke-bryta |
Aktiverad som standard i .NET 9 | Som förslag |
Orsak
Den här regeln utlöses när den identifierar en beteendeförändring mellan .NET 6 och .NET 7 som introduceras av de nya inbyggda operatorerna för IntPtr och UIntPtr.
Regelbeskrivning
Med den numeriska IntPtr-funktionen IntPtrhar du UIntPtr fått inbyggda operatorer för konverteringar, unary-åtgärder och binära åtgärder. Dessa operatorer kan utlösas när de flödar över i markerad kontext eller kanske inte genererar omarkerad kontext jämfört med tidigare användardefinierade operatorer i .NET 6 och tidigare versioner. Du kan stöta på den här beteendeförändringen när du uppgraderar till .NET 7.
Lista över API:er som påverkas
Operator | Kontext | I .NET 7 | I .NET 6 och tidigare | Exempel |
---|---|---|---|---|
operator +(IntPtr, int) | markerad | Kastar när spill | Kastar inte när spill | checked(intPtrVariable + 2); |
operator -(IntPtr, int) | markerad | Kastar när spill | Kastar inte när spill | checked(intPtrVariable - 2); |
explicit operatorn IntPtr(long) | Okontrollerat | Kastar inte när spill | Kan kasta in 32-bitarskontexter | (IntPtr)longVariable; |
explicit operator void*(IntPtr) | markerad | kastar när spill | Kastar inte när spill | checked((void*)intPtrVariable); |
explicit operator IntPtr(void*) | markerad | kastar när spill | Kastar inte när spill | checked((IntPtr)voidPtrVariable); |
explicit operator int(IntPtr) | Okontrollerat | Kastar inte när spill | Kan kasta in 64-bitarskontexter | (int)intPtrVariable; |
operator +(UIntPtr, int) | markerad | Kastar när spill | Kastar inte när spill | checked(uintPtrVariable + 2); |
operator -(UIntPtr, int) | markerad | Kastar när spill | Kastar inte när spill | checked(uintPtrVariable - 2); |
explicit operator UIntPtr(ulong) | Okontrollerat | Kastar inte när spill | Kan kasta in 32-bitarskontexter | (UIntPtr)uLongVariable |
explicit operator uint(UIntPtr) | Okontrollerat | Kastar inte när spill | Kan kasta in 64-bitarskontexter | (uint)uintPtrVariable |
Så här åtgärdar du överträdelser
Granska koden för att avgöra om det flaggade uttrycket kan orsaka en beteendeförändring och välj ett lämpligt sätt att åtgärda diagnostiken från följande alternativ:
Åtgärda alternativ:
- Om uttrycket inte skulle orsaka en beteendeförändring:
IntPtr
Om typen ellerUIntPtr
används som inbyggtint
elleruint
ändrar du typen tillnint
ellernuint
.IntPtr
Om typen ellerUIntPtr
används som en inbyggd pekare ändrar du typen till motsvarande inbyggda pekartyp.- Om du inte kan ändra variabeltypen utelämnar du varningen.
- Om uttrycket kan orsaka en beteendeförändring kan du omsluta det med en
checked
ellerunchecked
-instruktion för att bevara det tidigare beteendet.
Exempel
Överträdelse:
using System;
public unsafe class IntPtrTest
{
IntPtr intPtrVariable;
long longVariable;
void Test ()
{
checked
{
IntPtr result = intPtrVariable + 2; // Warns: Starting with .NET 7 the operator '+' will throw when overflowing in a checked context. Wrap the expression with an 'unchecked' statement to restore the .NET 6 behavior.
result = intPtrVariable - 2; // Starting with .NET 7 the operator '-' will throw when overflowing in a checked context. Wrap the expression with an 'unchecked' statement to restore the .NET 6 behavior.
void* voidPtrVariable = (void*)intPtrVariable; // Starting with .NET 7 the explicit conversion '(void*)IntPtr' will throw when overflowing in a checked context. Wrap the expression with an 'unchecked' statement to restore the .NET 6 behavior.
result = (IntPtr)voidPtrVariable; // Starting with .NET 7 the explicit conversion '(IntPtr)void*' will throw when overflowing in a checked context. Wrap the expression with an 'unchecked' statement to restore the .NET 6 behavior.
}
intPtrVariable = (IntPtr)longVariable; // Starting with .NET 7 the explicit conversion '(IntPtr)Int64' will not throw when overflowing in an unchecked context. Wrap the expression with a 'checked' statement to restore the .NET 6 behavior.
int a = (int)intPtrVariable; // Starting with .NET 7 the explicit conversion '(Int32)IntPtr' will not throw when overflowing in an unchecked context. Wrap the expression with a 'checked' statement to restore the .NET 6 behavior.
}
}
Lösningen
- Om uttrycket inte skulle orsaka en beteendeförändring och
IntPtr
typen ellerUIntPtr
används som inbyggtint
elleruint
ändrar du typen tillnint
ellernuint
.
using System;
public unsafe class IntPtrTest
{
nint intPtrVariable; // type changed to nint
long longVariable;
void Test ()
{
checked
{
nint result = intPtrVariable + 2; // no warning
result = intPtrVariable - 2;
void* voidPtrVariable = (void*)intPtrVariable;
result = (nint)voidPtrVariable;
}
intPtrVariable = (nint)longVariable;
int a = (int)intPtrVariable;
}
}
- Om uttrycket kan orsaka en beteendeförändring kan du omsluta det med en
checked
ellerunchecked
-instruktion för att bevara det tidigare beteendet.
using System;
public unsafe class IntPtrTest
{
IntPtr intPtrVariable;
long longVariable;
void Test ()
{
checked
{
IntPtr result = unchecked(intPtrVariable + 2); // wrap with unchecked
result = unchecked(intPtrVariable - 2);
void* voidPtrVariable = unchecked((void*)intPtrVariable);
result = unchecked((IntPtr)voidPtrVariable);
}
intPtrVariable = checked((IntPtr)longVariable); // wrap with checked
int a = checked((int)intPtrVariable);
}
}
När du ska ignorera varningar
Om uttrycket inte skulle orsaka en beteendeförändring är det säkert att ignorera en varning från den här regeln.