CA2020: Evitar el cambio de comportamiento causado por los operadores integrados de IntPtr/UIntPtr
Propiedad | Value |
---|---|
Identificador de la regla | CA2020 |
Título | Evitar el cambio de comportamiento causado por operadores integrados de IntPtr/UIntPtr |
Categoría | Confiabilidad |
La corrección es problemática o no problemática | Poco problemático |
Habilitado de forma predeterminada en .NET 8 | Como sugerencia |
Causa
Esta regla se desencadena cuando detecta un cambio de comportamiento entre .NET 6 y .NET 7 introducido por los nuevos operadores integrados de IntPtr y UIntPtr.
Descripción de la regla
Con la característica IntPtr numérico, IntPtr y UIntPtr obtuvieron operadores integrados para conversiones, operaciones unarias y operaciones binarias. Estos operadores pueden generar una excepción en los desbordamientos dentro de un contexto comprobado o pueden no generar una excepción en un contexto no comprobado en comparación con los operadores definidos por el usuario anteriores en .NET 6 y versiones anteriores. Es posible que encuentre este cambio de comportamiento al actualizar a .NET 7.
Lista de API afectadas
Operador | Context | En .NET 7 | En .NET 6 y versiones anteriores | Ejemplo |
---|---|---|---|---|
operador +(IntPtr, int) | Activado | Genera una excepción en los desbordamientos | No se produce en los desbordamientos | checked(intPtrVariable + 2); |
operador -(IntPtr, int) | Activado | Genera una excepción en los desbordamientos | No se produce en los desbordamientos | checked(intPtrVariable - 2); |
operador explícito IntPtr(long) | unchecked | No se produce en los desbordamientos | Puede generar una excepción en contextos de 32 bits | (IntPtr)longVariable; |
operador explícito void*(IntPtr) | Activado | Genera una excepción en los desbordamientos | No se produce en los desbordamientos | checked((void*)intPtrVariable); |
operador explícito IntPtr(void*) | Activado | Genera una excepción en los desbordamientos | No se produce en los desbordamientos | checked((IntPtr)voidPtrVariable); |
operador explícito int(IntPtr) | unchecked | No se produce en los desbordamientos | Puede generar una excepción en contextos de 64 bits | (int)intPtrVariable; |
operador +(UIntPtr, int) | Activado | Genera una excepción en los desbordamientos | No genera una excepción en los desbordamientos | checked(uintPtrVariable + 2); |
operador -(UIntPtr, int) | Activado | Genera una excepción en los desbordamientos | No genera una excepción en los desbordamientos | checked(uintPtrVariable - 2); |
operador explícito UIntPtr(ulong) | unchecked | No se produce en los desbordamientos | Puede generar una excepción en contextos de 32 bits | (UIntPtr)uLongVariable |
operador explícito uint(UIntPtr) | unchecked | No se produce en los desbordamientos | Puede generar una excepción en contextos de 64 bits | (uint)uintPtrVariable |
Cómo corregir infracciones
Examine el código para determinar si la expresión marcada podría provocar un cambio de comportamiento y elegir una manera adecuada de corregir el diagnóstico entre las siguientes opciones:
Opciones de corrección:
- Si la expresión no provocaría un cambio de comportamiento:
- Si el tipo
IntPtr
oUIntPtr
se usan como un tipoint
ouint
nativo, cambie el tipo anint
onuint
. - Si el tipo
IntPtr
oUIntPtr
se usan como un puntero nativo, cambie el tipo al tipo de puntero nativo correspondiente. - Si no puede cambiar el tipo de la variable, suprima la advertencia.
- Si el tipo
- Si la expresión podría provocar un cambio de comportamiento, puede encapsularla con una instrucción
checked
ounchecked
para conservar el comportamiento anterior.
Ejemplo
Infracción:
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.
}
}
Corrección:
- En caso de que la expresión no provoque un cambio de comportamiento y el tipo
IntPtr
oUIntPtr
se usa como un tipoint
ouint
nativo, cambie el tipo anint
onuint
.
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;
}
}
- Si la expresión podría provocar un cambio de comportamiento, puede encapsularla con una instrucción
checked
ounchecked
para conservar el comportamiento anterior.
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);
}
}
Cuándo suprimir las advertencias
Si la expresión no provocaría un cambio de comportamiento, es seguro suprimir una advertencia de esta regla.