Share via


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

Property Värde
Regel-ID CA2020
Title Förhindra beteendeförändringar som orsakas av inbyggda operatorer av IntPtr/UIntPtr
Kategori Tillförlitlighet
Korrigeringen är icke-bakåtkompatibel Icke-icke-bryta
Aktiverad som standard i .NET 8 Som förslag

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 den numeriska IntPtr-funktionen IntPtrhar du UIntPtr fått inbyggda operatorer för konverteringar, unary-åtgärder och binära åtgärder. 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 Sammanhang 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) markerad Kastar när spill Kastar inte när spill checked(intPtrVariable - 2);
explicit operatorn IntPtr(long) Okontrollerat Kastar inte när spill Kan kasta in 32-bitarskontexter (IntPtr)longVariable;
explicit operator void*(IntPtr) markerad kastar när spill Kastar inte när spill checked((void*)intPtrVariable);
explicit operator IntPtr(void*) markerad kastar när spill Kastar inte när spill checked((IntPtr)voidPtrVariable);
explicit operator int(IntPtr) Okontrollerat Kastar inte när spill Kan kasta in 64-bitarskontexter (int)intPtrVariable;
operator +(UIntPtr, int) markerad Kastar när spill Kastar inte när spill checked(uintPtrVariable + 2);
operator -(UIntPtr, int) markerad Kastar när spill Kastar inte när spill checked(uintPtrVariable - 2);
explicit operator UIntPtr(ulong) Okontrollerat Kastar inte när spill Kan kasta in 32-bitarskontexter (UIntPtr)uLongVariable
explicit operator uint(UIntPtr) Okontrollerat Kastar inte när spill Kan kasta in 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:

Åtgärda alternativ:

  • Om uttrycket inte skulle orsaka en beteendeförändring:
    • IntPtr Om typen eller UIntPtr används som inbyggt int eller uintändrar du typen till nint eller nuint.
    • IntPtr Om typen eller UIntPtr används som en inbyggd pekare ändrar du typen till motsvarande inbyggda pekartyp.
    • 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