علاقه مند به مهندسی نرم افزار
ویژگی Primary Constructors در سی شارپ 12
در سی شارپ 12 ، ویژگی های مختلفی معرفی شدهاند که یکی از آن ها Primary Constructors نام دارد.
مزایای استفاده از Primary Constructors در سی شارپ عبارتند از :
بهبود خوانایی کدها و درک سریعتر آن ها : استفاده از Primary Constructor باعث کاهش تکرار کدها و افزایش خوانایی آنها میشود.
پذیرش مستقیم Dependency ها توسط پارامتر ها.
عدم نیاز به استفاده از کلمه کلیدی this برای مقدار دهی به Property های سازنده.
تولید کدهای بهینهشده و بهبوداتی در کارایی : استفاده از Primary Constructor باعث بهبود کارایی کدها میشود.
می خواییم ببینیم Primary Constructor علاوه بر کدنویسی تمیزتر و کوتاهتر چه محدودیت هایی هم داره؟ با چن تا مثال به همراه کدنویسی ویژگی ها و محدودیت های Primary Constructor و همچنین به تفاوت primary constructor class و primary constructor record می پردازیم :
خب اگه بخواییم یه فیلدی رو اساین کنیم توی یه کلاس و در زمان ساخت این مقدار و بگیریم و فورس کنیم که حتما بهمون مقدار بده میاییم Constructor می سازیم یعنی :
public class Student
{
private readonly int _id;
public Student(int id)
{
_id = id;
}
}
اینجا id رو میگیریم و اساین می کنیم. مثل تمام سرویس هایی که inject می کنیم. مثلا :
public class StudentService
{
private readonly IStudentProvider _studentProvider;
public StudentService(IStudentProvider studentProvider)
{
_studentProvider = studentProvider;
}
}
خب IStudentProvider رو inject می کنیم. Primary Constructor میگه اگه (int id) رو بیاری جلو اسم کلاس
یعنی : { } public class Student (int id) ، دیگه نیازی نیست اینارو بنویسی :
private readonly int _id;
public Student (int id)
{
_id = id;
}
من برات همه رو می نویسم و هر جایی که داری از این فیلد یعنی id_ استفاده میکنی من برات هندلش می کنم پس نیازی به تعریف ;private readonly int _id و تعریف Constructor نیست. تمام این ها به عنوانPrimary Constructor میاد این بالا :
public class Student (int id)
{
}
ولی این یه محدودیتی داره ، محدودیتش این که این مقدار :
private readonly int _id;
public Student (int id)
{
_id = id;
}
هنگام کامپایل به یه همچین کدی تبدیل میشه :
public class Student_Compiled
{
private int _srutokjdmvnghtyoeks456lsk_id;
public Student_Compiled (int id)
{
_srutokjdmvnghtyoeks456lsk_id = id;
}
}
اولین تفاوتی که میبینیم readonly نداره ، وقتی از Primary Constructor استفاده می کنیم فیلدی که برای ما میسازه ، readonly نیستش. پس یکی از محدودیت های Primary Constructor این که readonly رو متوجه نمیشه. اگه بخواییم readonly رو داشته باشیم ، بیاییم یک فیلد readonly تعریف کنیم. دیگه مستقیما با خود این id کار نکنیم. یعنی : ;private readonly int _id = id ، که id رو اساین کنیم بهش و با id_ کار کنیم. فقط برای اینکه اون constructor رو ننویسیم. پس اولین محدودیت Primary Constructor این که readonly تبدیل نمیشه. دومین محدودیتش این که id رو داریم :
public class Student(int id)
{
public string ToString()
{
id = 123;
return id.ToString();
}
}
زمان کامپایل این id میاد داخل constructor :
public Student_Compiled(int id)
{
}
یه فیلد درست میکنه که اسمش رو نمیدونیم چیه : ;srutokjdmvnghtyoeks456lsk_id_ ؟؟؟ فقط خود کامپایلر می فهمتش و جاگزاری میکنه ، جاهایی که نیاز داریم یعنی این id دقیقا تبدیل شده به این : ;srutokjdmvnghtyoeks456lsk_id_ ، محدودیتش این که id رو داریم ولی نمیتونیم بگیم this.id ، بخاطر این که کامپایلر نمیدونه اینو که داریم می نویسیم this.id ، تبدیل به چی کنه؟ پس چون نمیدونیم و هنگام کامپایل این اتفاق میفته پس نمیتونیم از کلمه this استفاده کنیم، فقط مستقیما میتونیم از id استفاده کنیم.
مثلا : ;id = 123 ، چون وقتی کامپایل میشه این id میاد داخل constructor و تبدیل به فیلد میشه و چون نمیدونیم کامپایلر قراره چه عددی اینجا ;srutokjdmvnghtyoeks456lsk_id_ بزاره پس به واسطه همین از کلمه کلیدی this.id نمیتونیم استفاده کنیم.
خب بریم مثال بعدی از Primary Constructor :
تو کلاس Student میتونیم چن تا Constructor داشته باشیم : یعنی یه Constructor Default ،
public class Student
{
private readonly int _id;
public Student()
{
}
public Student(int id)
{
_id = id;
}
}
و یه Constructor که اینطوری id رو بگیریم. اما اگه (int id) رو بزاریم این جا :
public class Student(int id)
{
}
دیگه نیازی به تعریف فیلد نیست ، ولی هنگام استفاده از Primary Constructor اگه دیفالت Constructor می خواییم ، باید this رو بنویسیم یه default value هم بهش بدیم :
public Student() : this (15)
{
}
حتما باید این کارو انجام بدیم تا Default Constructor برامون ساخته بشه. اینم یکی از امکاناتی که اگه از Primary Constructor و Default Constructor بخواییم هم زمان استفاده کنیم باید از this(15) استفاده کنیم تا بتونیم کامپایل کنیم.
خب یه مثال دیگه از Primary Constructor :
یه کلاس Entity داریم با یه Constructor :
public class Entity
{
public Entity(int id)
{
}
}
و یه کلاس Student :
public class Student : Entity
{
public Student(int id) : base(id)
{
}
}
با base اشاره داریم به کلاس Entity ، خب اگه این کلاس Entity مون Default Constructor بگیره :
public class Entity(int id)
{
}
پس :
public Entity(int id)
{
}
حذف میشه ، این جا از کلاس Student و base(id) داریم استفاده می کنیم ، اگه کلاس Student رو Default Constructor کنیم :
public class Student(int id) : Entity
{
}
دیگه base , constructor نداریم ، میاییم مستقیما id رو بهش میدیم :
public class Student(int id) : Entity(id)
{
}
کلمه کلیدی base دیگه نیازی نیست.
تفاوت Primary Constructor Class با Primary Constructor Record :
public record Student_Record(int Id);
خب این Id مون ، Pascal ، یعنی تبدیل میشه به یه پراپرتی.
public class Student(int id)
{
public string ToString()
{
return id.ToString();
}
}
و این id مون ، Camel Case ، یعنی تبدیل میشه به یه فیلد.
اگه از Student_Record یه instance بگیریم :
public class Program
{
public static void Main(string[] args)
{
Student_Record record = new(14);
// record.Id
}
}
میتونیم Id رو ببینیم ، تبدیل میشه به یه پراپرتی. اما وقتی از Student یه instance بگیریم :
public class Program
{
public static void Main(string[] args)
{
Student student = new(14);
// student.id
}
}
نمیتونیم id رو ببینیم ، تبدیل میشه به یه فیلد.
پس فرق record با class متفاوت بودنشون از این جهت که :
public record Student_Record(int Id);
این Id تبدیل به یه پراپرتی میشه. ولی :
public class Student(int id)
{
}
این id تبدیل به یه فیلد میشه و همچنین در کلاس کلمه کلیدی this رو نداریم. یعنی this.id نمی بینیم. چون نمیدونیم قراره کامپایلر تبدیل به چه عددی بکنه ، مثل این :
private int _srutokjdmvnghtyoeks456lsk_id;
بخاطر همین از this.id نمیتونیم استفاده کنیم ، فقط مستقیما از id استفاده می کنیم.
خب این از قابلیت Primary Constructor ، محدودیت ها و بهینه تر بودنش.
مطلبی دیگر از این انتشارات
کاربرد فایل gitkeep.
مطلبی دیگر از این انتشارات
چطور برنامه نویسی را شروع کنیم ؟
مطلبی دیگر از این انتشارات
ساخت دشمن ساده در یونیتی بدون navmesh