CA2020: Mencegah perubahan perilaku yang disebabkan oleh operator bawaan IntPtr/UIntPtr
Properti | Nilai |
---|---|
ID Aturan | CA2020 |
Judul | Mencegah perubahan perilaku yang disebabkan oleh operator bawaan IntPtr/UIntPtr |
Golongan | Keandalan |
Perbaikan bersifat disruptif atau non-disruptif | Non-disruptif |
Diaktifkan secara default di .NET 9 | Sebagai saran |
Penyebab
Aturan ini diaktifkan ketika mendeteksi perubahan perilaku antara .NET 6 dan .NET 7 yang diperkenalkan oleh operator bawaan baru dan IntPtrUIntPtr.
Deskripsi aturan
Dengan fitur IntPtr numerik, IntPtr dan UIntPtr mendapatkan operator bawaan untuk konversi, operasi unary, dan operasi biner. Operator ini mungkin melempar saat meluap dalam konteks yang diperiksa atau mungkin tidak dilemparkan dalam konteks yang tidak dicentang dibandingkan dengan operator yang ditentukan pengguna sebelumnya di .NET 6 dan versi yang lebih lama. Anda mungkin mengalami perubahan perilaku ini saat memutakhirkan ke .NET 7.
Daftar API yang terpengaruh
Operator | Konteks | Dalam .NET 7 | Di .NET 6 dan yang lebih lama | Contoh |
---|---|---|---|---|
operator +(IntPtr, int) | dicentang | Melempar ketika luapan | Tidak melempar ketika luapan | checked(intPtrVariable + 2); |
operator -(IntPtr, int) | dicentang | Melempar ketika luapan | Tidak melempar ketika luapan | checked(intPtrVariable - 2); |
Operator eksplisit IntPtr(long) | yang tidak dicentang | Tidak melempar ketika luapan | Dapat melemparkan dalam konteks 32-bit | (IntPtr)longVariable; |
operator eksplisit batal*(IntPtr) | dicentang | melempar ketika luapan | Tidak melempar ketika luapan | checked((void*)intPtrVariable); |
operator eksplisit IntPtr(void*) | dicentang | melempar ketika luapan | Tidak melempar ketika luapan | checked((IntPtr)voidPtrVariable); |
int operator eksplisit(IntPtr) | yang tidak dicentang | Tidak melempar ketika luapan | Dapat melemparkan dalam konteks 64-bit | (int)intPtrVariable; |
operator +(UIntPtr, int) | dicentang | Melempar ketika luapan | Tidak melempar ketika luapan | checked(uintPtrVariable + 2); |
operator -(UIntPtr, int) | dicentang | Melempar ketika luapan | Tidak melempar ketika luapan | checked(uintPtrVariable - 2); |
UIntPtr(ulong) operator eksplisit | yang tidak dicentang | Tidak melempar ketika luapan | Dapat melemparkan dalam konteks 32-bit | (UIntPtr)uLongVariable |
uint operator eksplisit(UIntPtr) | yang tidak dicentang | Tidak melempar ketika luapan | Dapat melemparkan dalam konteks 64-bit | (uint)uintPtrVariable |
Cara memperbaiki pelanggaran
Periksa kode Anda untuk menentukan apakah ekspresi yang ditandai dapat menyebabkan perubahan perilaku, dan pilih cara yang sesuai untuk memperbaiki diagnostik dari opsi berikut:
Opsi perbaikan:
- Jika ekspresi tidak akan menyebabkan perubahan perilaku:
-
IntPtr
Jika jenis atauUIntPtr
digunakan sebagai asliint
atauuint
, ubah jenis menjadinint
ataunuint
. -
IntPtr
Jika jenis atauUIntPtr
digunakan sebagai penunjuk asli, ubah jenis ke jenis penunjuk asli yang sesuai. - Jika Anda tidak dapat mengubah jenis variabel, tekan peringatan.
-
- Jika ekspresi dapat menyebabkan perubahan perilaku, bungkus dengan
checked
pernyataan atauunchecked
untuk mempertahankan perilaku sebelumnya.
Contoh
Pelanggaran:
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.
}
}
Perbaikan:
- Jika ekspresi tidak akan menyebabkan perubahan perilaku dan
IntPtr
jenis atauUIntPtr
digunakan sebagai asliint
atauuint
, ubah jenis menjadinint
ataunuint
.
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;
}
}
- Jika ekspresi dapat menyebabkan perubahan perilaku, bungkus dengan
checked
pernyataan atauunchecked
untuk mempertahankan perilaku sebelumnya.
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);
}
}
Kapan harus menekan peringatan
Jika ekspresi tidak akan menyebabkan perubahan perilaku, aman untuk menekan peringatan dari aturan ini.