في هذه الصفحة
ايه المميزات اللى ممكن تحصل عليها بسطر واحد فقط من الـ Code Snippet ده ؟!
record Employee(string FirstName, string LastName, double Salary);
الإجابة هتلاقيها بنفسك لما تبص في الـ Code Snippet الجاي :
public class Employee
{
// properties
public string FirstName { get; }
public string LirstName { get; }
public double Salary { get; }
// constructor
public Employee(string firstName, string lastName, double salary)
{
FirstName = firstName;
LastName = lastName;
Salary = salary;
}
// optional: you can override toString() for better representation
public override string toString()
{
return $"Employee {FirstName} {LastName}, Salary: {Salary}";
}
// optional: you can override Equals() and GetHashCode() for value comparison
public override bool Equals(object obj)
{
if(obj is Employee otherEmployee)
{
return FirstName == otherEmployee.FirstName &&
LastName == otherEmployee.LastName &&
Salary == otherEmployee.Salary;
}
return false;
}
public override int GetHashCode()
{
return HashCode.Combine(FirstName, LastName, Salary);
}
}
تخيل كل الـ Class اللى فى الـ Code Snippet التاني بكل الـ Features اللى فيه زى :
- الـ Immutability
- الـ Comparison base on values
- الـ Print ‘ToString’
بالإضافة لمميزات تانية لسه هنتكلم عليها، انت قدرت تحصل عليها بسطر واحد فقط من الـ Code عن طريق استخدام Record
يلا نبدا ونشوف الكلام ده بيحصل ازاى و نتعرف أكتر على الـ Record و بعد المقال ده هتفهمه كويس وهتقدر تطبقه و تستفيد منه فى شغلك بشكل جميل.
بداية الـ Record
أولا ال Record نزل مع ال C#9 / Dotnet 5 ومهم هنا تبقى عارف الـ Features المهمة نزلت امتى عشان لو نقلت من Project للتانى أو من شركه للتانية تبقى عارف ايه الادوات اللى معاك وازاى تقدر تستخدمها، و مهم طبعا تبقى مطلع على كل ما هو جديد عشان تستفيد من التحسينات اللى بتنزل كل فترة والـ Code بتاعك يبقى أحسن و ميبقاش Legacy بمرور السنين
طيب ايه هو ال Record وايه مميزاته؟
طبقا للتعريف اللى على موقع Microsoft
“A record in C# is a class or struct that provides special syntax and behavior for working with data models. The record modifier instructs the compiler to synthesize members that are useful for types whose primary role is storing data”
فهو نوع معين من الـ Class / Struct
” اللى هما فى الأخر عبارة عن “Container” بيقدر يشيل جواه Data أو Behavior أو الاتنين مع بعض “لكن ليه خصائص مختلفة و مميزة عن الأنواع دى و عن طريق استخدام الـ Record Modifier فقط هتقدر تستفيد بكل الخصائص و هتساعدك تتعامل مع الـ Data بشكل أسهل زى ما شوفنا فى أول مثال.
فبطريقة مختصرة جداً ال Record هو عبارة عن طريقة مبسطة للتعامل مع الـ Data
تعالوا نبدأ بالـ Record اللى موجود فى C#9 / Dotnet 5 “ ونتكلم عنه هنا فى جزء لوحده عشان لو حد لسه شغال بالـ Version دى يعرف ايه هي المميزات اللي هياخدها من الـ Record وايه المميزات الاضافية لما يطلع لـ Version أعلى ، وبالمناسبة مفيش تغييرات حصلت بل فيه اضافات فأنت حتى لو شغال ب Version أعلى فهتكون محتاج الجزء ده عشان نبني عليه.
لحد الـ Version دى كان Record عبارة عن Reference Type فقط ويستخدم كبديل للـ Classes لنقل الـ Data بالاضافة لبعض المميزات التانية:
1- Immutability
أول حاجة وأهم حاجه هى الـ Immutability وهى ببساطة انك متقدرش تعدل فى الـ Data اللى شايلها الـ Object أو كما يطلق عليها Object State بعد ما يحصله Create / Initialization و دى حاجه مهمة جدا بتحميك من مشاكل كتير خاصة لو الـ Object بتاعك بيروح من مكان لمكان فبتضمن ان محدش هيغير فيه فى الطريق من غير ما انت تاخد بالك وبالتالى هيقلل المشاكل الغير متوقعة، وعشان كده هتلاقى مستخدمة فى فيديوهات و مقالات أكتر الوقت كـ DTO أو Data Transfer Object وهى Types بتستخدم لنقل البيانات من مكان للتانىتعالوا نشوف ال Immutability فى المثال الجاى ده
هتلاقى هنا علطول حصل Compiler Error بيوقفك و يقولك انك متقدرش تعدل فى ال Property وانك تقدر بس تحط Value ليها اثناء الـ Initialization
2- Comparison Based on Values
مقارنة الـ Reference Types بناءا على ال Values مش على الـ Reference و ده لم يكن موجود ابدًا فى الـ Class وكنت بتحتاج تكتبلها Custom Code زى ما شوفنا فى ال Class الموجودة فى أول المقال .. لكن باستخدام ال Record تقدر فقط تعمل الاتى:
var employee1 = new Employee("Mohamed", "Magdi", 1000);
var employee2 = new Employee("Mohamed", "Magdi", 1000);
var employee3 = new Employee("Ammar", "Ali", 2000);
Console.WriteLine($"Is Equal = {employee1} {employee2}"); // Output: IsEqual = True
Console.WriteLine($"Is Equal = {employee1} {employee3}"); // Output: IsEqual = False
record Employee(string FirstName, string LastName, double Salary);
طبعا عشان نحقق نفس الكلام باستخدام الـ Class العاديه كنا هنروح نـ Override ال Equals Method عشان نغير ال Behavior بتاعها زى ما شوفنا فى المثال اللى فى أول المقال
3- Concise Way to Define a Reference Type with Immutable Properties
طريقة مختصرة جدا عشان تعرف Reference Type ب Immutable Typesوعشان كنا نعمل كده باستخدام الـ Class كنا هنكتب أكثر وأصعب و طبعا كل ما كان الكود مختصر هيبقى أسهل في القراءة والصيانة
record Employee(string FirstName, string LastName, double Salary);
4- Built-in Copy Constructor
ميزة كمان مهمة وهي انك تعمل Object جديد باستخدام Object قديم و تنسخ نفس البيانات اللي فيه وتقدر برده تغير اللى انت عايزه
public record Person(string FirstName, string LastName);
public static void main()
{
Person person1 = new("Mohamed", "Magdi");
Console.WriteLine(person1);
// output: Person {FirstName = Mohamed, LastName = Magdi}
Person person2 = person1 with { FirstName = "Mahmoud" };
Console.WriteLine(person1 == person2); // output: False
Person person3 = person1;
Console.WriteLine(person3);
// output: Person {FirstName = Mohamed, LastName = Magdi}
}
5- Built-in Formatting for Display
وهنا من غير ما تكتب أي Code لو جيت تطبع ال Object بتاعك كـ Text عن طريق الـ ToString() Default Implementation زى المثال الجاى:
var employee1 = new Employee("Mohamed", "Magdi", 100);
Console.WriteLine(employee1); // Output: Employee { FirstName = Mohamed, LastName = Magdi, Salary = 1000}
record Employee(string FirstName, string LastName, double Salary);
6- Support for Inheritance Hierarchies
وهنا المقصود انك تقدر تـ Extend الـ Record زى ما بتعمل مع ال Class زى المثال اللى جاى
public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade) : Person(FirstName, LastName);
public record Student(string FirstName, string LastName, int Grade) : Person(FirstName, LastName);
public static void main()
{
Person teacher = new Teacher("Mohamed", "Magdi", 3);
Person student = new Student("Mohamed", "Magdi", 3);
Console.WriteLine(teacher == student); // output: False
Student student2 = new Student("Mohamed", "Magdi", 3);
Console.WriteLine(student2 == student); // output: True
}
هنا ال Output الأول قيمته بـ False عشان هو بيقارن Type و Values مش Values بس
طيب الـ Record ده طلع كويس، امتى استخدمه؟
1- Simple Data Transfer Objects (DTO)
اللى بتستخدم فى نقل البيانات من Layer للتانية
2- Lightweight Types without Behavior
أنواع خفيفة مش محتاج منها Behavior محتاج بس انها تشيل Data
3- Immutable Data Models
لو عايز ابنى Data Models محدش يقدر يغير فى ال State بتاعتها
4- Improve Safety and Containment
تغيير الـ State لما بيكون بس من خلال الـ Constructor بيخلى ال Behavior متوقع أكتر
5- Avoid Bugs from Unexpected State Mutation
مشاكل كتير بتحصل من التغيير غير المتوقع للـ State من أى مكان و باستخدام الـ Records هتقدر تمنع المشاكل دى عن طريق ال Immutability
طيب امتى مستخدموش؟
- لو عايز مستوى أعلى من التحكم فى خصائص الـ Container بتاعك، احنا شوفنا ان الـ Records بيديك شوية Functionalities جاهزة و الحاجات دى مش هتقدر تتحكم فيها أو تغيرها بعكس الـ Class مثلا تقدر تتحكم أكتر و تغير الـ Behavior بتاع الـ Equals و ال toString وشوية حاجات تانية كمان
- لو عايز تستفيد بخصائص كتير من الـ Inheritance و Polymorphism هنا الـ Record مش هيبقى Flexible معاك بشكل كافى و برده الـ Class هتكون خيار أفضل
- لو عايز تسمح بالـ Immutability و ماعندكش مشكله فى تغيير الـ State الخاصة بالـ Object وقتها الـ Class هيكون الخيار الأفضل
وبكده يخلص الجزء الأول اللى اتكلمنا فيه عن الـ Records وايه هى مميزاتها و امتى استخدمها و امتى مستخدمهاشاتكلمنا على الـ Record Reference Type و ده الجزء اللى نزل مع DotNet 5 C#9 / و حاولنا نخلى الموضوع بسيط عشان الناس تقدر تطبق و تستفيد فورا بعد ما تخلص الجزء ده.
و الجزء اللى جاى ان شاء الله هنتكلم عن الاضافات اللى نزلت فى ال C#10/Dotnet 6 و ازاى بدأ يدعم ال Value Type كمان عن طريق Struct Record و هنشوف كمان حاجات Advanced عن الـ Record حالات استخدام تانيه و طرق تانيه لكتابته و تأثيره على الكود.