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.
Ushbu bo‘lim mundarijasi
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 #
string? ism = null;
try
{
Console.WriteLine(ism.Length);
}
catch (NullReferenceException x)
{
Console.WriteLine($"Qulash: {x.GetType().Name}");
}
Qulash: NullReferenceException
null obyekt emas - unda Length ham, boshqa hech narsa ham yo'q.
Unga murojaat qilish dasturni to'xtatadi.
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:
| Yozuv | Ma'nosi |
|---|---|
string ism | null bo'lmasligi kerak |
string? ism | null bo'lishi mumkin |
Kompilyator ? bor turlarni tekshirmasdan ishlatsangiz
ogohlantiradi:
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;
Topilmadi
Kompilyator null ni tekshirmasangiz ogohlantiradi, lekin
dasturni baribir quradi.
Buni haqiqiy xatoga aylantirish uchun .csproj ga qo'shing:
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Jiddiy loyihalarda buni yoqish tavsiya etiladi: aks holda ogohlantirishlar to'planib ketadi va hech kim ularga qaramay qo'yadi.
?. - xavfsiz murojaat #
string? bor = "Namangan";
string? yoq = null;
Console.WriteLine(bor?.Length);
Console.WriteLine(yoq?.Length ?? -1);
Console.WriteLine(yoq?.ToUpper() ?? "(qiymat yo'q)");
8
-1
(qiymat yo'q)
?. shunday ishlaydi: chap tomon null bo'lsa, butun ifoda
null bo'ladi va o'ng tomon umuman bajarilmaydi.
?? va ??= #
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);
Salom, Mehmon
sukut qiymati
sukut qiymati
| Operator | Nima 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:
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; }
}
Namangan
manzil yo'q
?. bo'lmaganida har bir bosqichni alohida if bilan tekshirish
kerak bo'lardi.
! - "men bilaman, null emas" #
string? qiymat = "Toshkent";
// Kompilyatorga: bu yerda null emasligiga kafolat beraman
int uzunlik = qiymat!.Length;
Console.WriteLine($"Uzunligi: {uzunlik}");
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 #
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}");
}
True
True
True
Uzun matn: matn
is null va == null farqiIkkalasi 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:
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; }
}
Husanboy - Informatika
Ism ni bermasdan obyekt yaratsangiz, kompilyator xato beradi:
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 #
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"}");
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 #
| Holat | Nima qilish |
|---|---|
Metod null qaytarishi mumkin | Qaytish turini ? bilan belgilang |
Parametr null bo'lmasligi kerak | ? siz e'lon qiling |
| Xossa albatta kerak | required |
| Sukut qiymat bor | ?? |
| Zanjir bo'ylab murojaat | ?. |
| Ogohlantirishni o'chirgingiz keldi | To'xtang - kodni qayta o'ylang |
null emasBu eng foydali amaliy qoidalardan biri:
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"] : [];
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.
nullo'zgaruvchiga murojaat qilib, istisnoni ko'ring.string?e'lon qilib, kompilyator ogohlantirishini kuzating.?.bilan xavfsiz murojaat qiling.??bilan sukut qiymat bering.??=ni ikki marta chaqirib, natijani ko'ring.- Ikki darajali zanjirda
?.ni sinang. is nullva== nullfarqini o'z so'zingiz bilan yozing.requiredxossali sinf yarating va uni bermasdan obyekt yaratib ko'ring.int?bilan "qiymat berilmagan" holatni ifodalang.nullqaytaruvchi metodni bo'sh ro'yxat qaytaradigan qilib qayta yozing.
Xulosa #
nullga murojaatNullReferenceExceptionberadi - eng ko'p uchraydigan qulash sababi.<Nullable>enable</Nullable>yoqilgandastringvastring?farqlanadi.- Bu ogohlantirish darajasida; jiddiy loyihada
TreatWarningsAsErrorsyoqing. ?.-nullbo'lsa chaqirmaydi;??- sukut qiymat beradi.!himoyani o'chiradi, muammoni hal qilmaydi - undan qoching.- Tekshirish uchun
is nullvais not null. requiredxossa o'rnatilmay qolishining oldini oladi.- Metoddan
nullemas, bo'sh to'plam qaytaring.
Keyingi bo'limda istisnolar bilan ishlashni o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
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.