Aracılığıyla paylaş


CA2020: IntPtr/UIntPtr'nin yerleşik işleçlerinden kaynaklanan davranış değişikliğini önleme

Özellik Değer
Kural Kimliği CA2020
Başlık IntPtr/UIntPtr yerleşik işleçlerinin neden olduğu davranış değişikliğini önleme
Kategori Güvenilirlik
Hataya neden olan veya bozulmayan düzeltme Hataya neden olmayan
.NET 8'de varsayılan olarak etkin Öneri olarak

Neden

Bu kural, ve UIntPtr'nin yeni yerleşik işleçleri IntPtr tarafından sunulan .NET 6 ile .NET 7 arasında davranışsal bir değişiklik algıladığında tetiklenir.

Kural açıklaması

Sayısal IntPtr özelliğiyle ve UIntPtr dönüştürmeler, IntPtr birli işlemler ve ikili işlemler için yerleşik işleçler kazandı. Bu işleçler, denetlenen bağlam içinde taşma olduğunda veya .NET 6 ve önceki sürümlerde kullanıcı tanımlı önceki işleçlerle karşılaştırıldığında işaretsiz bağlam oluşturmayabilir. .NET 7'ye yükseltirken bu davranış değişikliğiyle karşılaşabilirsiniz.

Etkilenen API'lerin listesi

İşleç Bağlam .NET 7'de .NET 6 ve önceki sürümlerde Örnek
operator +(IntPtr, int) checked Taşma olduğunda atar Taşmalar olduğunda atmıyor checked(intPtrVariable + 2);
operator -(IntPtr, int) checked Taşma olduğunda atar Taşmalar olduğunda atmıyor checked(intPtrVariable - 2);
açık işleç IntPtr(long) unchecked Taşmalar olduğunda atmıyor 32 bit bağlamlar oluşturabilir (IntPtr)longVariable;
explicit işleci void*(IntPtr) checked taşma olduğunda atar Taşmalar olduğunda atmıyor checked((void*)intPtrVariable);
açık işleç IntPtr(void*) checked taşma olduğunda atar Taşmalar olduğunda atmıyor checked((IntPtr)voidPtrVariable);
explicit operator int(IntPtr) unchecked Taşmalar olduğunda atmıyor 64 bit bağlamlar oluşturabilir (int)intPtrVariable;
operator +(UIntPtr, int) checked Taşma olduğunda atar Taşmalar olduğunda atmıyor checked(uintPtrVariable + 2);
operator -(UIntPtr, int) checked Taşma olduğunda atar Taşmalar olduğunda atmıyor checked(uintPtrVariable - 2);
açık işleç UIntPtr(ulong) unchecked Taşmalar olduğunda atmıyor 32 bit bağlamlar oluşturabilir (UIntPtr)uLongVariable
açık işleç uint(UIntPtr) unchecked Taşmalar olduğunda atmıyor 64 bit bağlamlar oluşturabilir (uint)uintPtrVariable

İhlalleri düzeltme

Bayrak eklenmiş ifadenin davranış değişikliğine neden olup olmadığını belirlemek için kodunuzu inceleyin ve aşağıdaki seçeneklerden tanılamayı düzeltmek için uygun bir yol seçin:

Düzeltme seçenekleri:

  • İfade davranış değişikliğine neden olmayacaksa:
    • IntPtr veya UIntPtr türü yerel int veya uintolarak kullanılıyorsa, türünü nint veya nuintolarak değiştirin.
    • IntPtr veya UIntPtr türü yerel işaretçi olarak kullanılıyorsa, türü ilgili yerel işaretçi türüyle değiştirin.
    • Değişkenin türünü değiştiremiyorsanız uyarıyı bastırın.
  • İfade bir davranış değişikliğine neden olabilirse, önceki davranışı korumak için bir checked veya unchecked deyimiyle sarmalayın.

Örnek

İhlal:

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.
    }
}

Düzeltme:

  • İfade davranışsal bir değişikliğe neden olmayacaksa ve IntPtr veya UIntPtr türü yerel int veya uintolarak kullanılıyorsa, türünü nint veya nuintolarak değiştirin.
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;
    }
}
  • İfade bir davranış değişikliğine neden olabilirse, önceki davranışı korumak için bir checked veya unchecked deyimiyle sarmalayın.
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);
    }
}

Uyarıların ne zaman bastırılması gerekiyor?

İfade davranışsal bir değişikliğe neden olmayacaksa, bu kuraldan gelen bir uyarıyı bastırmak güvenlidir.

Ayrıca bkz.