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
Kategori Keandalan
Perbaikan bersifat merusak atau tidak merusak Tidak terputus
Diaktifkan secara default di .NET 10 Sebagai saran
Bahasa yang berlaku C#

Penyebab

Aturan ini diaktifkan ketika mendeteksi perubahan perilaku antara .NET 6 dan .NET 7 yang disebabkan oleh operator bawaan baru IntPtr dan UIntPtr.

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) diperiksa 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*) ditandai melempar ketika luapan Tidak melempar ketika luapan checked((IntPtr)voidPtrVariable);
operator eksplisit int(IntPtr) tidak dicentang Tidak melempar ketika luapan Dapat melakukan throw 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);
operator eksplisit UIntPtr(ulong) yang tidak dicentang Tidak melempar ketika luapan Dapat melemparkan dalam konteks 32-bit (UIntPtr)uLongVariable
explicit operator uint(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:
    • Jika jenis IntPtr atau UIntPtr digunakan sebagai jenis bawaan int atau uint, ubah jenis menjadi nint atau nuint.
    • Jika jenis IntPtr atau UIntPtr digunakan sebagai pointer asli, ubah jenis ke tipe pointer asli yang sesuai.
    • Jika Anda tidak dapat mengubah jenis variabel, abaikan peringatannya.
  • Jika ekspresi dapat menyebabkan perubahan perilaku, bungkus dengan pernyataan checked atau unchecked 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 jenis IntPtr atau UIntPtr digunakan sebagai tipe asli int atau uint, ubah jenis menjadi nint atau nuint.
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 ekspresi tersebut dengan pernyataan checked atau unchecked 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.

Lihat juga