12-bo‘lim

null xavfsizligi

null nima va nega xavfli, nullable havola turlari, ? va ! belgilari, ?. va ?? operatorlari, required a'zolar va null tekshiruvining to'g'ri usullari.

🕑 14 daqiqa o‘qish 📄 762 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Muammo nimada
  2. Nullable havola turlari
  3. ?. - xavfsiz murojaat
  4. ?? va ??=
  5. Zanjir bo'ylab
  6. ! - "men bilaman, null emas"
  7. Tekshirishning to'g'ri usullari
  8. required - majburiy xossalar
  9. Qiymat turlari uchun null
  10. Amaliy qoidalar
  11. Xulosa

null - "bu yerda hech narsa yo'q" degani. U foydali, lekin dasturlashdagi eng ko'p xatoning sababi hisoblanadi.

C# 8 dan boshlab kompilyator bu xatolarning katta qismini oldindan topa oladi.

Muammo nimada #

CSHARP
string? ism = null;

try
{
    Console.WriteLine(ism.Length);
}
catch (NullReferenceException x)
{
    Console.WriteLine($"Qulash: {x.GetType().Name}");
}
Natija
Qulash: NullReferenceException

null obyekt emas - unda Length ham, boshqa hech narsa ham yo'q. Unga murojaat qilish dasturni to'xtatadi.

"Bir milliard dollarlik xato"

null tushunchasini 1965-yilda ingliz olimi Tony Hoare kiritgan. Keyinchalik u buni "mening bir milliard dollarlik xatom" deb atagan:

Uning hisobicha, null sabab bo'lgan qulashlar, zaifliklar va tuzatish ishlari o'tgan qirq yilda shuncha zarar keltirgan.

Zamonaviy tillar - C#, Kotlin, Rust, TypeScript - hammasi bu muammoni turli yo'llar bilan hal qilishga harakat qilmoqda.

Nullable havola turlari #

.csproj da <Nullable>enable</Nullable> yoqilgan bo'lsa (yangi loyihalarda sukut bo'yicha shunday), kompilyator ikki turni farqlaydi:

YozuvMa'nosi
string ismnull bo'lmasligi kerak
string? ismnull bo'lishi mumkin

Kompilyator ? bor turlarni tekshirmasdan ishlatsangiz ogohlantiradi:

CSHARP
string? topilgan = Qidir("Malika");

// Ogohlantirish: topilgan null bo'lishi mumkin
if (topilgan is not null)
{
    Console.WriteLine($"Uzunligi: {topilgan.Length}");
}
else
{
    Console.WriteLine("Topilmadi");
}

string? Qidir(string ism) => ism == "Husanboy" ? ism : null;
Natija
Topilmadi
Bu faqat ogohlantirish, xato emas

Kompilyator null ni tekshirmasangiz ogohlantiradi, lekin dasturni baribir quradi.

Buni haqiqiy xatoga aylantirish uchun .csproj ga qo'shing:

XML
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

Jiddiy loyihalarda buni yoqish tavsiya etiladi: aks holda ogohlantirishlar to'planib ketadi va hech kim ularga qaramay qo'yadi.

?. - xavfsiz murojaat #

CSHARP
string? bor = "Namangan";
string? yoq = null;

Console.WriteLine(bor?.Length);
Console.WriteLine(yoq?.Length ?? -1);
Console.WriteLine(yoq?.ToUpper() ?? "(qiymat yo'q)");
Natija
8
-1
(qiymat yo'q)

?. shunday ishlaydi: chap tomon null bo'lsa, butun ifoda null bo'ladi va o'ng tomon umuman bajarilmaydi.

?? va ??= #

CSHARP
string? kiritilgan = null;

string ism = kiritilgan ?? "Mehmon";
Console.WriteLine($"Salom, {ism}");

string? sozlama = null;
sozlama ??= "sukut qiymati";
Console.WriteLine(sozlama);

sozlama ??= "bu o'rnatilmaydi";
Console.WriteLine(sozlama);
Natija
Salom, Mehmon
sukut qiymati
sukut qiymati
OperatorNima qiladi
??Chap tomon null bo'lsa, o'ngdagini beradi
??=Faqat null bo'lgandagina o'zlashtiradi
?.null bo'lsa, chaqirmaydi
?[]null bo'lsa, indekslamaydi

Zanjir bo'ylab #

?. operatorining kuchi zanjirda ko'rinadi:

CSHARP
var bilan = new Talaba { Manzil = new Manzil { Shahar = "Namangan" } };
var siz = new Talaba();

Console.WriteLine(bilan.Manzil?.Shahar ?? "manzil yo'q");
Console.WriteLine(siz.Manzil?.Shahar ?? "manzil yo'q");

class Talaba
{
    public Manzil? Manzil { get; set; }
}

class Manzil
{
    public string? Shahar { get; set; }
}
Natija
Namangan
manzil yo'q

?. bo'lmaganida har bir bosqichni alohida if bilan tekshirish kerak bo'lardi.

! - "men bilaman, null emas" #

CSHARP
string? qiymat = "Toshkent";

// Kompilyatorga: bu yerda null emasligiga kafolat beraman
int uzunlik = qiymat!.Length;

Console.WriteLine($"Uzunligi: {uzunlik}");
Natija
Uzunligi: 8
! - ogohlantirishni o'chirish, muammoni hal qilish emas

! belgisi kompilyatorga "ishonaver" deydi. Lekin u hech narsani tekshirmaydi.

Agar siz xato qilgan bo'lsangiz, dastur baribir NullReferenceException bilan quladi - faqat endi kompilyator sizni ogohlantirmagan bo'ladi.

Ya'ni ! ishlatish - himoyani o'chirish. Uni faqat quyidagi holatda qo'llang: kompilyator ko'ra olmaydigan, siz esa aniq biladigan sabab bo'lsa.

Ko'p hollarda to'g'ri javob boshqa: kodni shunday qayta yozingki, qiymat haqiqatan null bo'lmasin.

Tekshirishning to'g'ri usullari #

CSHARP
string? a = null;
string? b = "matn";

Console.WriteLine(a is null);
Console.WriteLine(b is not null);
Console.WriteLine(string.IsNullOrWhiteSpace(a));

if (b is { Length: > 2 } uzun)
{
    Console.WriteLine($"Uzun matn: {uzun}");
}
Natija
True
True
True
Uzun matn: matn
is null va == null farqi

Ikkalasi ham ishlaydi, lekin is null ishonchliroq.

Sababi: == operatorini sinf o'zi qayta belgilashi mumkin va u kutilmagan ish qilishi mumkin. is null esa til darajasidagi tekshiruv - uni o'zgartirib bo'lmaydi.

Shu sababli zamonaviy C# da is null va is not null tavsiya etiladi.

required - majburiy xossalar #

C# 11 dan xossani majburiy qilish mumkin:

CSHARP
var t = new Talaba { Ism = "Husanboy", Yonalish = "Informatika" };
Console.WriteLine($"{t.Ism} - {t.Yonalish}");

class Talaba
{
    public required string Ism { get; init; }
    public required string Yonalish { get; init; }
}
Natija
Husanboy - Informatika

Ism ni bermasdan obyekt yaratsangiz, kompilyator xato beradi:

Natija
error CS9035: Required member 'Talaba.Ism' must be set
in the object initializer or attribute constructor.

Bu null muammosini kelib chiqish joyida hal qiladi: xossa hech qachon o'rnatilmay qolmaydi.

Qiymat turlari uchun null #

CSHARP
int? yosh = null;

Console.WriteLine($"Qiymati bormi: {yosh.HasValue}");
Console.WriteLine($"Qiymat: {yosh ?? -1}");

yosh = 25;
Console.WriteLine($"Endi: {yosh.Value}");

int[] sonlar = [];
int? birinchi = sonlar.Length > 0 ? sonlar[0] : null;
Console.WriteLine($"Birinchi element: {birinchi?.ToString() ?? "yo'q"}");
Natija
Qiymati bormi: False
Qiymat: -1
Endi: 25
Birinchi element: yo'q

int odatda null bo'la olmaydi, lekin int? bo'la oladi. Bu "qiymat berilmagan" holatni ifodalash uchun kerak - masalan bazadagi bo'sh maydon.

Amaliy qoidalar #

HolatNima qilish
Metod null qaytarishi mumkinQaytish turini ? bilan belgilang
Parametr null bo'lmasligi kerak? siz e'lon qiling
Xossa albatta kerakrequired
Sukut qiymat bor??
Zanjir bo'ylab murojaat?.
Ogohlantirishni o'chirgingiz keldiTo'xtang - kodni qayta o'ylang
Bo'sh to'plam qaytaring, null emas

Bu eng foydali amaliy qoidalardan biri:

CSHARP
Console.WriteLine(
    Yomon("yo'q") is null ? "null keldi" : "ro'yxat keldi");
Console.WriteLine($"Yaxshi: {Yaxshi("yo'q").Count} ta element");

List<string>? Yomon(string q) => q == "bor" ? ["a"] : null;
List<string> Yaxshi(string q) => q == "bor" ? ["a"] : [];
Natija
null keldi
Yaxshi: 0 ta element

Birinchi metoddan keyin har bir chaqiruvchi null ni tekshirishi kerak. Ikkinchisidan keyin esa natijani darhol foreach ga berish mumkin - bo'sh ro'yxat bo'ylab yurish xavfsiz.

Xuddi shu qoida satrlarga ham tegishli: null o'rniga "" qaytaring.

Amaliy topshiriq
  1. null o'zgaruvchiga murojaat qilib, istisnoni ko'ring.
  2. string? e'lon qilib, kompilyator ogohlantirishini kuzating.
  3. ?. bilan xavfsiz murojaat qiling.
  4. ?? bilan sukut qiymat bering.
  5. ??= ni ikki marta chaqirib, natijani ko'ring.
  6. Ikki darajali zanjirda ?. ni sinang.
  7. is null va == null farqini o'z so'zingiz bilan yozing.
  8. required xossali sinf yarating va uni bermasdan obyekt yaratib ko'ring.
  9. int? bilan "qiymat berilmagan" holatni ifodalang.
  10. null qaytaruvchi metodni bo'sh ro'yxat qaytaradigan qilib qayta yozing.

Xulosa #

  • null ga murojaat NullReferenceException beradi - eng ko'p uchraydigan qulash sababi.
  • <Nullable>enable</Nullable> yoqilganda string va string? farqlanadi.
  • Bu ogohlantirish darajasida; jiddiy loyihada TreatWarningsAsErrors yoqing.
  • ?. - null bo'lsa chaqirmaydi; ?? - sukut qiymat beradi.
  • ! himoyani o'chiradi, muammoni hal qilmaydi - undan qoching.
  • Tekshirish uchun is null va is not null.
  • required xossa o'rnatilmay qolishining oldini oladi.
  • Metoddan null emas, bo'sh to'plam qaytaring.

Keyingi bo'limda istisnolar bilan ishlashni o'rganamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.