CA2020: Förhindra beteendeförändring som orsakas av inbyggda operatorer av IntPtr/UIntPtr

Egenskap Värde
Regel-ID CA2020
Title Förhindra beteendeförändringar som orsakas av inbyggda operatorer av IntPtr/UIntPtr
Kategori Tillförlitlighet
Korrigeringen är antingen invasiv eller icke-invasiv Oumbrytbar
Aktiverad som standard i .NET 10 Som förslag
Tillämpliga språk C#

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 funktionen numeric IntPtr har IntPtr och UIntPtr fått inbyggda operatorer för konverteringar, unära operationer och binära operationer. 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

Operatör 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) kontrollerad Kastar när det överskrider Kastar inte när det överflödar checked(intPtrVariable - 2);
explicit operator IntPtr(long) Okontrollerat Slänger inte vid överflöde Kan utlösa i 32-bitarskontexter (IntPtr)longVariable;
explicit operator void*(IntPtr) markerad kastar när spill Kastar inte vid överflöde checked((void*)intPtrVariable);
explicit operator IntPtr(void*) kontrollerad kastar när spill Kastar inte vid överflöde checked((IntPtr)voidPtrVariable);
explicit operator int(IntPtr) Okontrollerat Kastar inte vid överskridande Kan hantera 64-bitarskontexter (int)intPtrVariable;
operator +(UIntPtr, int) markerad Kastar när det överskrider Kastar inte vid överskridande checked(uintPtrVariable + 2);
operator -(UIntPtr, int) markerad Kastar när det överskrider Kastar inte vid överskridande checked(uintPtrVariable - 2);
explicit operator UIntPtr(ulong) Okontrollerat Kastar inte vid överskridande Kan utlösa i 32-bitarskontexter (UIntPtr)uLongVariable
explicit operator uint(UIntPtr) Okontrollerat Kastar inte vid överskridande Kan utlösas i 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:

Alternativ för felsökning

  • Om uttrycket inte skulle orsaka en beteendeförändring:
    • Om typen IntPtr eller UIntPtr används som ett nativt int eller uint, ändra typen till nint eller nuint.
    • Om IntPtr-typen eller UIntPtr-typen används som en inbyggd pekare, ändra typen till den motsvarande inbyggda pekartypen.
    • 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 eller unchecked -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 eller UIntPtr används som inbyggt int eller uintändrar du typen till nint eller 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;
    }
}
  • Om uttrycket kan orsaka en beteendeförändring kan du omsluta det med en checked eller unchecked -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.

Se även