علاقه مند به مهندسی نرم افزار
ویژگی 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 ، محدودیت ها و بهینه تر بودنش.
مطلبی دیگر از این انتشارات
آشنایی با module resolution در انگولار
مطلبی دیگر از این انتشارات
اصطلاحات php
مطلبی دیگر از این انتشارات
خداحافظی با هزینههای سنگین! رقیبی قدرتمند برای کوپایلوت