تنفيذ أساليب الامتداد لفئة
عادة، هناك طريقتان لإضافة أسلوب إلى نوع موجود:
- تعديل التعليمات البرمجية المصدر لهذا النوع. يؤدي تعديل المصدر إلى إنشاء تغيير فاصل إذا قمت أيضا بإضافة أي حقول بيانات خاصة لدعم الأسلوب.
- تعريف الأسلوب الجديد في فئة مشتقة. لا يمكن إضافة أسلوب بهذه الطريقة باستخدام التوريث لأنواع أخرى، مثل البنيات والتعدادات. كما لا يمكن استخدامه "لإضافة" أسلوب إلى فئة مختومة.
تتيح لك أساليب الملحق "إضافة" أسلوب إلى نوع موجود دون تعديل النوع نفسه أو تنفيذ الأسلوب الجديد في نوع موروث. لا يجب أن يتواجد أسلوب الملحق أيضا في نفس التجميع مثل النوع الذي يوسعه. يمكنك استدعاء أسلوب ملحق كما لو كان عضوا معرفا من نوع.
أساليب الامتداد
تمكنك أساليب الملحق من "إضافة" أساليب إلى الأنواع الموجودة دون إنشاء نوع مشتق جديد أو إعادة التحويل البرمجي أو تعديل النوع الأصلي بطريقة أخرى. أساليب الملحق هي أساليب ثابتة، ولكن يتم استدعاؤها كما لو كانت أساليب مثيل على النوع الموسع. بالنسبة إلى التعليمات البرمجية للعميل المكتوبة بلغة C# وF# وVisual Basic، لا يوجد فرق واضح بين استدعاء أسلوب ملحق والأساليب المعرفة في نوع.
ربط أساليب الامتداد في وقت التحويل البرمجي
يمكنك استخدام أساليب الامتداد لتوسيع فئة أو واجهة، ولكن ليس لتجاوزها. لا يتم استدعاء أسلوب ملحق بنفس الاسم والتوقيع كأسلوب فئة. في وقت التحويل البرمجي، يكون لأساليب الامتداد دائما أولوية أقل من أساليب المثيل المحددة في النوع نفسه. بمعنى آخر، إذا كان النوع يحتوي على أسلوب يسمى Process(int i)، وكان لديك أسلوب ملحق بنفس التوقيع، فإن المحول البرمجي يربط دائما بأسلوب المثيل. عندما يواجه المحول البرمجي استدعاء أسلوب، فإنه يبحث عن تطابق في أساليب مثيل النوع. إذا لم يتم العثور على أسلوب مثيل مطابق، يبحث المحول البرمجي عن أي أساليب ملحق محددة للنوع. يرتبط المحول البرمجي بأسلوب الملحق الأول الذي يعثر عليه.
يوضح المثال التالي القواعد التي يتبعها المحول البرمجي C# في تحديد ما إذا كان يجب ربط استدعاء أسلوب إلى أسلوب مثيل على النوع، أو إلى أسلوب ملحق.
namespace ExtensionMethodDemo.PersonNamespace
{
// Define a simple class with properties and methods
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public void Introduce()
{
Console.WriteLine($"Hi, I'm {FirstName} {LastName}, and I'm {Age} years old.");
}
}
}
namespace ExtensionMethodDemo.PersonExtensionsNamespace
{
using ExtensionMethodDemo.PersonNamespace;
// Define an extension method for the Person class
public static class PersonExtensions
{
public static void DisplayFullName(this Person person)
{
Console.WriteLine($"Full Name: {person.FirstName} {person.LastName}");
}
public static bool IsAdult(this Person person)
{
return person.Age >= 18;
}
public static void Introduce()
{
Console.WriteLine($"Extension - Hi, it's nice to meet you.");
}
// Extension method attempting to override Introduce
public static void Introduce(this Person person, string greeting)
{
Console.WriteLine($"{greeting}, I'm {person.FirstName} {person.LastName}, and I'm {person.Age} years old.");
}
}
}
namespace ExtensionMethodDemo
{
using ExtensionMethodDemo.PersonNamespace;
using ExtensionMethodDemo.PersonExtensionsNamespace;
class Program
{
static void Main(string[] args)
{
// Create instances of the Person class
Person person1 = new Person { FirstName = "FName1", LastName = "LName1", Age = 25 };
Person person2 = new Person { FirstName = "FName2", LastName = "LName2", Age = 16 };
// Use the methods of the Person class
person1.Introduce();
person2.Introduce();
// Use the extension methods
person1.DisplayFullName();
Console.WriteLine($"Is {person1.FirstName} an adult? {person1.IsAdult()}");
person2.DisplayFullName();
Console.WriteLine($"Is {person2.FirstName} an adult? {person2.IsAdult()}");
// Use the extension method that attempts to override Introduce
person1.Introduce("Hello");
person2.Introduce("Greetings");
}
}
}
// Output:
// Hi, I'm FName1 LName1, and I'm 25 years old.
// Hi, I'm FName2 LName2, and I'm 16 years old.
// Full Name: FName1 LName1
// Is FName1 an adult? True
// Full Name: FName2 LName2
// Is FName2 an adult? False
// Hello, I'm FName1 LName1, and I'm 25 years old.
// Greetings, I'm FName2 LName2, and I'm 16 years old.
في هذا المثال، تحتوي فئة Person على ثلاث خصائص: FirstNameLastNameAge. تحتوي فئة Person أيضا على أسلوب مثيل Introduce يكتب رسالة إلى وحدة التحكم.
تحدد فئة PersonExtensions أساليب الامتداد لفئة Person. تحتوي فئة PersonExtensions على أساليب الامتداد التالية:
-
DisplayFullName: يكتب الاسم الكامل للشخص إلى وحدة التحكم. -
IsAdult: إرجاع قيمة منطقية تشير إلى ما إذا كان الشخص بالغا. -
Introduce: يكتب رسالة إلى وحدة التحكم. يحتوي هذا الأسلوب على تحميلين زائدين: أحدهما بدون معلمات والآخر بمعلمة سلسلة. -
Introduce(this Person person, string greeting): يكتب رسالة إلى وحدة التحكم مع تحية مخصصة. -
Introduce(): يكتب رسالة افتراضية إلى وحدة التحكم.
ينشئ الأسلوب Main مثيلين من فئة Person ويستدعي أسلوب Introduce على كل مثيل. يتم تنفيذ الأسلوب Introduce المحدد في فئة Person. لا يتم استدعاء الأسلوب Introduce بدون معلمات في فئة PersonExtensions لأن فئة Person لديها بالفعل أسلوب مثيل Introduce بنفس التوقيع. يتبع المحول البرمجي قواعد أساليب ملحق الربط في وقت التحويل البرمجي ويعطي الأولوية لأسلوب المثيل المحدد في النوع نفسه. يستدعي أسلوب Main أيضا أساليب الامتداد DisplayFullNameIsAdultوطريقة Introduce المحملة تحميلا زائدا بتحية مخصصة. يتم تنفيذ أساليب الملحق كما هو متوقع.
إرشادات عامة
تعد أساليب الملحق خيارا مهما لإنشاء وظائف قابلة لإعادة الاستخدام في جميع أنحاء النظام البنائي .NET. ومع ذلك، لا يزال من الأفضل تعديل التعليمات البرمجية للعنصر أو اشتقاق نوع جديد كلما كان ذلك معقولا وممكنا. تعد أساليب الامتداد خيارا ممتازا عندما لا يكون المصدر الأصلي تحت سيطرتك، أو عندما يكون العنصر المشتق غير مناسب أو مستحيلا، أو عندما لا ينبغي الكشف عن الوظيفة خارج نطاقها القابل للتطبيق.
عند استخدام أساليب الامتداد لتوسيع نوع لا تتحكم فيه التعليمات البرمجية المصدر، فإنك تخاطر بأن يؤدي التغيير في تنفيذ النوع إلى قطع أسلوب الملحق الخاص بك. إذا قمت بتنفيذ أساليب الامتداد لنوع معين، فتذكر النقاط التالية:
- لا يتم استدعاء أسلوب ملحق إذا كان له نفس التوقيع كأسلوب معرف في النوع.
- يتم إدخال أساليب الملحق في النطاق على مستوى مساحة الاسم. على سبيل المثال، إذا كان لديك فئات ثابتة متعددة تحتوي على أساليب ملحق في مساحة اسم واحدة تسمى
Extensions، إحضارها جميعا إلى النطاق بواسطة توجيهusing Extensions;.
بالنسبة لمكتبة الفئات التي قمت بتنفيذها، يجب عدم استخدام أساليب الامتداد لتجنب زيادة رقم إصدار التجميع. إذا كنت ترغب في إضافة وظائف مهمة إلى مكتبة تملك التعليمات البرمجية المصدر لها، فاتبع إرشادات .NET لتعيين إصدار التجميع.