11-bo‘lim
struct va record
Qiymat turlarini o'zingiz yaratish, struct va class farqi, record turlari, tenglik qoidalari, with ifodasi va qaysi birini tanlash.
Ushbu bo‘lim mundarijasi
Shu paytgacha class bilan ishladik. C# da yana ikkita tur e'lon qilish
usuli bor va ularning har biri boshqa muammoni hal qiladi.
struct - o'zingiz yaratgan qiymat turi #
struct class ga o'xshaydi, lekin u qiymat turi: nusxalanadi,
havola qilinmaydi.
var a = new Nuqta(3, 4);
var b = a; // NUSXA olinadi
b.X = 100;
Console.WriteLine($"a = ({a.X}, {a.Y})");
Console.WriteLine($"b = ({b.X}, {b.Y})");
Console.WriteLine($"a dan boshgacha masofa: {a.Masofa():F2}");
struct Nuqta(double x, double y)
{
public double X { get; set; } = x;
public double Y { get; set; } = y;
public double Masofa() => Math.Sqrt(X * X + Y * Y);
}
a = (3, 4)
b = (100, 4)
a dan boshgacha masofa: 5.00
b ni o'zgartirish a ga ta'sir qilmadi - 3-bo'limdagi qiymat turi
qoidasi.
Xuddi shu kodni class bilan yozsangiz, natija butunlay boshqacha
bo'ladi:
var a = new Nuqta(3, 4);
var b = a; // HAVOLA nusxalanadi
b.X = 100;
Console.WriteLine($"a = ({a.X}, {a.Y})");
Console.WriteLine($"b = ({b.X}, {b.Y})");
class Nuqta(double x, double y)
{
public double X { get; set; } = x;
public double Y { get; set; } = y;
}
a = (100, 4)
b = (100, 4)
Bitta so'z - struct o'rniga class - natijani butunlay o'zgartirdi.
Ikkala kod ham kompilyatsiya qilinadi va xato bermaydi. Farq faqat ishlash paytida ko'rinadi.
Agar struct ni metodga uzatib, uni o'zgartirsangiz, asl nusxa
o'zgarmaydi va bu ko'pincha kutilmagan bo'ladi.
Shuning uchun zamonaviy tavsiya: struct ni o'zgarmas qiling -
{ get; init; } yoki readonly struct ishlating. Shunda chalkashlik
uchun sabab qolmaydi.
struct qachon kerak #
| Shart | Izoh |
|---|---|
| Kichik (odatda 16 baytgacha) | Nusxalash arzon bo'lsin |
| Mantiqan bitta qiymat | Nuqta, rang, pul miqdori |
| O'zgarmas | Yaratilgandan keyin o'zgarmasin |
| Juda ko'p yaratiladi | Xotira yukini kamaytiradi |
Bu shartlarning hammasi bajarilmasa - class ishlating.
struct har uzatilganda to'liq nusxalanadi. Ichida 10 ta maydon
bo'lsa, har bir metod chaqiruvida 10 ta qiymat ko'chiriladi.
class da esa faqat havola (8 bayt) uzatiladi, obyekt qanchalik
katta bo'lishidan qat'i nazar.
Ya'ni katta struct - sekinlashtiruvchi omil, tezlashtiruvchi emas.
record - ma'lumot saqlash uchun #
record - asosan ma'lumot tashiydigan turlar uchun. U ko'p
narsani o'zi yozib beradi:
var t1 = new Talaba("Husanboy", 25);
var t2 = new Talaba("Husanboy", 25);
Console.WriteLine(t1);
Console.WriteLine($"Teng-mi: {t1 == t2}");
Console.WriteLine($"Xesh bir xilmi: {t1.GetHashCode() == t2.GetHashCode()}");
record Talaba(string Ism, int Yosh);
Talaba { Ism = Husanboy, Yosh = 25 }
Teng-mi: True
Xesh bir xilmi: True
Bitta qator kod uchun biz quyidagilarni bepul oldik:
- Konstruktor;
IsmvaYoshxossalari (initbilan);- Mazmunli
ToString(); - Qiymat bo'yicha tenglik (
==vaEquals); - Mos
GetHashCode().
Xuddi shuni class bilan yozsangiz, natija boshqacha:
var t1 = new Talaba("Husanboy", 25);
var t2 = new Talaba("Husanboy", 25);
Console.WriteLine(t1);
Console.WriteLine($"Teng-mi: {t1 == t2}");
class Talaba(string ism, int yosh)
{
public string Ism => ism;
public int Yosh => yosh;
}
Talaba
Teng-mi: False
class da == havolalarni solishtiradi: bular ikki xil obyekt,
demak teng emas. record da esa mazmun solishtiriladi.
Tasavvur qiling, talabalar ro'yxatida qidiryapsiz:
var royxat = new List<Talaba> { new("Husanboy", 25) };
Console.WriteLine(royxat.Contains(new Talaba("Husanboy", 25)));
record Talaba(string Ism, int Yosh);
True
record bo'lgani uchun Contains topdi. class bo'lganida False
chiqardi - garchi ma'lumot bir xil bo'lsa ham.
Xuddi shu narsa Dictionary kaliti, HashSet va Distinct() uchun
ham amal qiladi.
with - nusxa olib, bir qismini o'zgartirish #
var asl = new Mahsulot("Non", 4000, "Non mahsulotlari");
var arzon = asl with { Narx = 3500 };
Console.WriteLine(asl);
Console.WriteLine(arzon);
Console.WriteLine($"Asl o'zgarmadi: {asl.Narx}");
record Mahsulot(string Nom, decimal Narx, string Turkum);
Mahsulot { Nom = Non, Narx = 4000, Turkum = Non mahsulotlari }
Mahsulot { Nom = Non, Narx = 3500, Turkum = Non mahsulotlari }
Asl o'zgarmadi: 4000
with yangi obyekt yaratadi va faqat ko'rsatilgan xossani
o'zgartiradi. Qolgani nusxalanadi. Bu o'zgarmas ma'lumot bilan
ishlashning qulay usuli.
record struct #
record ning qiymat turi ko'rinishi ham bor:
var p1 = new Pul(15000, "UZS");
var p2 = p1 with { Miqdor = 20000 };
Console.WriteLine($"{p1} / {p2}");
Console.WriteLine($"Teng-mi: {p1 == p2}");
Console.WriteLine($"Nusxa teng-mi: {p1 == p1 with { }}");
readonly record struct Pul(decimal Miqdor, string Valyuta);
Pul { Miqdor = 15000, Valyuta = UZS } / Pul { Miqdor = 20000, Valyuta = UZS }
Teng-mi: False
Nusxa teng-mi: True
readonly record struct - kichik, o'zgarmas qiymatlar uchun eng yaxshi
tanlov: qiymat turi tezligi va record qulayligi birgalikda.
Uchtasini solishtirish #
class | struct | record | |
|---|---|---|---|
| Tur | Havola | Qiymat | Havola (sukut bo'yicha) |
| Tenglik | Havola bo'yicha | Qiymat bo'yicha | Qiymat bo'yicha |
ToString() | Tur nomi | Maydonlar | Maydonlar |
| Vorislik | Ha | Yo'q | Ha |
with ifodasi | Yo'q | Yo'q | Ha |
| Asosiy maqsad | Xatti-harakat | Kichik qiymat | Ma'lumot |
enum - nomlangan qiymatlar to'plami #
Holat[] holatlar = [Holat.Yangi, Holat.Jarayonda, Holat.Yakunlangan];
foreach (Holat holat in holatlar)
{
string izoh = holat switch
{
Holat.Yangi => "hali boshlanmagan",
Holat.Jarayonda => "ishlanmoqda",
Holat.Yakunlangan => "tugatilgan",
_ => "noma'lum"
};
Console.WriteLine($"{holat,-12} ({(int)holat}) - {izoh}");
}
enum Holat
{
Yangi,
Jarayonda,
Yakunlangan
}
Yangi (0) - hali boshlanmagan
Jarayonda (1) - ishlanmoqda
Yakunlangan (2) - tugatilgan
enum satrdan ancha yaxshiHolatni string bilan saqlash keng tarqalgan, lekin xavfli:
"jarayonda", "Jarayonda" va "jarayon" - kompilyator uchun uchta
turli qiymat va u xatoni topmaydi.
enum da esa noto'g'ri qiymat kompilyatsiya qilinmaydi. Bundan
tashqari muharrir mumkin bo'lgan qiymatlarni o'zi taklif qiladi.
Nuqtanistructqilib yozing va nusxa olinishini tekshiring.- Xuddi shuni
classqilib, farqni ko'ring. structqachon mos kelishini uchta shart bilan yozing.recordyarating va ikkita bir xil obyektni solishtiring.- Xuddi shu
recordniclassqilib,==natijasini solishtiring. List.Containsnirecordvaclassbilan sinab ko'ring.withifodasi bilan nusxa olib, bitta xossani o'zgartiring.readonly record structbilan pul turini yozing.- Uchta holatli
enumyarating vaswitchbilan ishlating. class,structvarecordni jadval ko'rinishida solishtiring.
Xulosa #
struct- qiymat turi: nusxalanadi, havola qilinmaydi.structfaqat kichik, o'zgarmas va ko'p yaratiladigan qiymatlar uchun; aks holdaclass.recordma'lumot turlari uchun: konstruktor,ToString, qiymat bo'yicha tenglik - hammasi bir qatorda.recordvaclassorasidagi farqContains,Distinct,Dictionarykaliti kabi joylarda bilinadi.withnusxa olib, bir qismini o'zgartiradi; asl obyekt o'zgarmaydi.readonly record struct- kichik o'zgarmas qiymatlar uchun eng yaxshi tanlov.enumholatni satr bilan saqlashdan xavfsizroq.- Ikkilansangiz -
class.
Keyingi bo'limda null xavfsizligini 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.