Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
| Ö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 |
| Düzeltme bozucu ya da bozmayan olabilir | Kesintisiz |
| .NET 10'da varsayılan olarak etkin | Öneri olarak |
| Geçerli diller | C# |
Neden
Bu kural, .NET 6 ile .NET 7 arasında IntPtr ve UIntPtr'in yeni yerleşik işleçlerinin neden olduğu davranışsal bir değişiklik algılandığında tetiklenir.
Kural açıklaması
Sayısal IntPtr özelliğiyle, IntPtr ve UIntPtr dönüştürmeler, birli işlemler ve ikili işlemler için yerleşik işleçler kazandı. Bu işleçler, denetlenen bağlamda taşma olduğunda istisna fırlatabilir veya denetlenmeyen bağlamda istisna fırlatmayabilir; bu durum, .NET 6 ve önceki sürümlerdeki kullanıcı tanımlı işleçlerle karşılaştırıldığında farklılık gösterebilir. .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) | kontrol edildi | Taşma olduğunda atar | Taşmalar olduğunda atmıyor | checked(intPtrVariable + 2); |
| operator -(IntPtr, int) | kontrol edildi | Taşma olduğunda atar | Taşmalar olduğunda atmıyor | checked(intPtrVariable - 2); |
| açık işleç IntPtr(long) | işaretlenmemiş | Taşmalar olduğunda atmıyor | 32 bit bağlamlar oluşturabilir | (IntPtr)longVariable; |
| explicit işleci void*(IntPtr) | kontrol edildi | taşma olduğunda atar | Taşmalar olduğunda atmıyor | checked((void*)intPtrVariable); |
| açık işleç IntPtr(void*) | Kontrol edildi | taşma olduğunda atar | Taşmalar olduğunda atmıyor | checked((IntPtr)voidPtrVariable); |
| explicit operator int(IntPtr) | işaretli değil | Taşmalar olduğunda atmıyor | 64 bit bağlamlar oluşturabilir | (int)intPtrVariable; |
| operator +(UIntPtr, int) | Kontrol edildi | Taşma olduğunda atar | Taşmalar olduğunda atmıyor | checked(uintPtrVariable + 2); |
| operator -(UIntPtr, int) | Kontrol edildi | Taşma olduğunda atar | Taşmalar olduğunda atmıyor | checked(uintPtrVariable - 2); |
| belirgin işleç UIntPtr(ulong) | işaretli değil | Taşmalar olduğunda atmıyor | 32 bit bağlamlar oluşturabilir | (UIntPtr)uLongVariable |
| açık işleç uint(UIntPtr) | işaretli değil | 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:
-
IntPtrveyaUIntPtrtürü yerelintveyauintolarak kullanılıyorsa, türününintveyanuintolarak değiştirin. -
IntPtrveyaUIntPtrtü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
checkedveyauncheckeddeyimiyle 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
IntPtrveyaUIntPtrtürü yerelintveyauintolarak kullanılıyorsa, türününintveyanuintolarak 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
checkedveyauncheckeddeyimiyle 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.