CA2020:防止 IntPtr/UIntPtr 內建運算子所造成的行為變更
屬性 | 值 |
---|---|
規則識別碼 | CA2020 |
職稱 | 防止 IntPtr/UIntPtr 內建運算子所造成的行為變更 |
類別 | 可靠性 |
修正程式是中斷或非中斷 | 不中斷 |
預設在 .NET 9 中啟用 | 建議 |
原因
當此規則偵測到 和 UIntPtr的新內建運算子IntPtr所引進的 .NET 6 與 .NET 7 之間的行為變更時,就會引發此規則。
檔案描述
使用數值 IntPtr 功能,IntPtr並UIntPtr取得轉換、一元運算和二進位運算的內建運算符。 相較於 .NET 6 和舊版中先前的使用者定義運算符,這些運算符可能會在檢查內容中溢位時擲回,或可能不會在未核取的內容中擲回。 升級至 .NET 7 時,可能會遇到此行為變更。
受影響的 API 清單
Operator | 上下文 | 在 .NET 7 中 | 在 .NET 6 和更早版本中 | 範例 |
---|---|---|---|---|
operator +(IntPtr, int) | checked | 溢位時擲回 | 當溢位時不會擲回 | checked(intPtrVariable + 2); |
operator -(IntPtr, int) | checked | 溢位時擲回 | 當溢位時不會擲回 | checked(intPtrVariable - 2); |
explicit 運算符 IntPtr(long) | unchecked | 當溢位時不會擲回 | 可以在32位內容中擲回 | (IntPtr)longVariable; |
explicit operator void*(IntPtr) | checked | 溢位時擲回 | 當溢位時不會擲回 | checked((void*)intPtrVariable); |
explicit 運算符 IntPtr(void*) | checked | 溢位時擲回 | 當溢位時不會擲回 | checked((IntPtr)voidPtrVariable); |
explicit operator int(IntPtr) | unchecked | 當溢位時不會擲回 | 可以在64位內容中擲回 | (int)intPtrVariable; |
operator +(UIntPtr, int) | checked | 溢位時擲回 | 當溢位時不會擲回 | checked(uintPtrVariable + 2); |
operator -(UIntPtr, int) | checked | 溢位時擲回 | 當溢位時不會擲回 | checked(uintPtrVariable - 2); |
explicit 運算符 UIntPtr(ulong) | unchecked | 當溢位時不會擲回 | 可以在32位內容中擲回 | (UIntPtr)uLongVariable |
explicit 運算符 uint(UIntPtr) | unchecked | 當溢位時不會擲回 | 可以在64位內容中擲回 | (uint)uintPtrVariable |
如何修正違規
檢查您的程式代碼,以判斷標幟的表達式是否可能導致行為變更,並選擇適當的方法來修正下列選項的診斷:
修正選項:
- 如果表達式不會造成行為變更:
IntPtr
如果使用 或UIntPtr
型別做為原生int
或uint
,請將類型變更為nint
或nuint
。IntPtr
如果使用 或UIntPtr
型別做為原生指標,請將類型變更為對應的原生指標類型。- 如果您無法變更變數的類型,請隱藏警告。
- 如果表達式可能會造成行為變更,請以
checked
或unchecked
語句包裝它,以保留先前的行為。
範例
違規:
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.
}
}
修正:
- 如果表示式不會造成行為變更,
IntPtr
且 或UIntPtr
類型會當做原生int
或uint
使用,請將類型變更為nint
或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;
}
}
- 如果表達式可能會造成行為變更,請以
checked
或unchecked
語句包裝它,以保留先前的行為。
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);
}
}
隱藏警告的時機
如果表達式不會造成行為變更,則隱藏來自此規則的警告是安全的。