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 9'da 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
Operatör | 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
veyaUIntPtr
türü yerelint
veyauint
olarak kullanılıyorsa, türününint
veyanuint
olarak değiştirin.IntPtr
veyaUIntPtr
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
veyaunchecked
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
veyaUIntPtr
türü yerelint
veyauint
olarak kullanılıyorsa, türününint
veyanuint
olarak 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
veyaunchecked
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.