Ban co biet viec chuyen tu constructor thong thuong sang primary constructor co the thay doi thoi diem cac field duoc khoi tao khong? Hay cung xem vi sao dieu nay quan trong.
Trong bai viet ngan nay, chung ta se xem su khac biet giua hai cach viet va dieu compiler thuc hien o ben duoi.
Mục lục
Van de
Hay tuong tuong ban co mot lop co so thuc hien mot so cong viec trong constructor, va cong viec do goi mot thanh vien virtual:
abstract class Base
{
protected Base(Func<int?> check)
{
Console.WriteLine($"{GetType().Name}: check() = {check()}, Message = {Message}");
}
protected abstract string Message { get; }
}
Phai, phai — goi thanh vien virtual trong constructor thuong la dau hieu cua mot van de thiet ke. Tuy nhien, trong thuc te, moi thu khong phai luc nao cung ro rang nhu vay. Trong bUnit, constructor cua lop co so WaitForHelper khoi dong mot timer. Khi timer kich hoat, no doc thuoc tinh virtual TimeoutErrorMessage. Van de van tuong tu, chi la bi an sau mot Timer va mot luong khac.
Bay gio, hay ke thua theo cach co dien:
class Regular : Base
{
private readonly int? count;
public Regular(int? count) : base(() => count)
{
this.count = count;
}
protected override string Message => $"count = {count?.ToString() ?? \"null\"}";
}
Va cung cach do voi primary constructor:
class Primary(int? count) : Base(() => count)
{
protected override string Message => $"count = {count?.ToString() ?? \"null\"}";
}
Trong co ve chung tuong duong, dung khong? Hay chay ca hai:
new Regular(3);
new Primary(3);
Regular: check() = 3, Message = count = null
Primary: check() = 3, Message = count = 3
Hoa ra chung khong tuong duong den the.
Compiler thuc hien dieu gi?
Neu xem phien ban ma compiler da ha cap — tac gia su dung ILSpy, nhung sharplab.io cung co the lam viec nay — su khac biet se tro nen ro rang. Day la lop Regular:
public Regular(int? count)
{
var obj = new <>c__DisplayClass1_0();
obj.count = count;
base..ctor(new Func<int?>(obj.<.ctor>b__0));
this.count = obj.count;
}
Lambda bat bien tham so trong mot closure, con goi la display class, vi the check() nhin thay dung gia tri. Tuy nhien, field this.count chi duoc gan sau khi constructor cua lop co so ket thuc. Moi viec ma constructor cua lop co so thuc hien trong khoang thoi gian do deu nhin thay gia tri null.
Con day la lop Primary:
public Primary(int? count)
{
<count>P = count;
base..ctor(new Func<int?>(<.ctor>b__0_0));
}
Vi count duoc su dung ben trong mot thanh vien, compiler luu no vao mot field an co ten <count>P. Field nay duoc gan truoc khi constructor cua lop co so duoc goi. Thu tu nay giong voi field initializer, von cung duoc chay truoc base(...) trong C#.
Vi vay, trong truong hop cua bUnit: voi constructor theo cach co dien, neu timer kich hoat truoc khi than constructor cua lop dan xuat chay, thong bao loi se la did not result in any matching element(s) thay vi did not result in exactly matching element(s). Voi primary constructor, gia tri da san sang tu truoc.
Luu y nho
Field <count>P duoc tao ra khong phai la readonly. Ban co the gan lai count ben trong lop, va compiler se khong ngan chan dieu do.
Neu can bao dam readonly, ban phai tu khai bao field. Mot field initializer nhu sau cung duoc chay truoc constructor cua lop co so:
private readonly int? count = count;
Tuy nhien, dung su dung tham so trong mot thanh vien dong thoi voi viec su dung no trong field initializer. Khi do, ban co hai ban sao cua cung mot gia tri, va compiler se canh bao voi ma CS9124.
Tom lai, primary constructor khong chi la cu phap rut gon. Cach compiler luu tru tham so va thu tu khoi tao co the tao ra khac biet quan trong, dac biet khi constructor cua lop co so goi thanh vien virtual hoac khoi dong cong viec bat dong bo.



