اکستنش متد ها ، این امکان رو در اختیار ما قرار میدن که بتونیم کد و فانکشنالیتی رو توی سرویس ها ( تایپ ، کلاس ، ... ) تغییر بدیم درصورتی که ما به اونها دسترسی نداریم و از طرفی به ما این امکان رو میدن که بتونیم کدی بنویسم که خوانا تر هست و خوندن اون برای دولوپر ها ، راحت تره!
توی این مقاله ، قراره با هم ببینیم که اکستنش متد ها چیا هستن ؟ اونا رو چجوری بنویسیم و چه موقع باید از اونا استفاده کنیم .
به طور کلی ، اکستنشن متد ها ، یک سری متد استاتیک ، توی کلاس های استاتیک هستن که به صورت متد هایی که بعد از اینستنس گرفتن از یک کلاسی برای ما دردسترس هستن ، استفاده میشن !
برای اینکه جمله بالا رو درک کنیم ، اول از همه یک متد استاتیک ، توی یک کلاس استاتیک ادد میکنیم :
اینجا ما یک کلاس استاتیک به اسم Extensions داریم که توی اون یک متد استاتیک به اسم AddAuthorName داریم. کل کاری که این متد انجام میده ، میاد و اسم مقاله و اسم نویسنده اون رو از ما میگیره و توی خروجی یک متن ، مثل متن زیر رو برای ما چاپ میکنه :
با فرض صحیح اضافه کردن namespace مربوط به کلاس Extensions ، کد ما کار میکنه و خروجی رو مثل بالا به ما میده !
حالا بیایم و فرض کنیم ما نمیخوایم هر سری که یک مقاله اضافه میکنیم ، یک کلاس و متد استاتیک رو اضافه کنیم و کدمون رو ( لاقل از لحاظ خواندن ) پیچیده کنیم. فرض کنیم که میخوایم کدمون به صورت زیر نوشته بشه :
همونطور که میدونیم ، توی تایپ string متدی به اسم AddAuthorName وجود نداره. آفرین ! درست حدس زدید .
اینجا دقیقا همونجایی هست که مفهوم اکستنشن متد میاد و پا به عرصه میذاره. الآن ، ما میخوایم اصطلاحا تایپ string که توسط Microsoft نوشته شده رو Extend کنیم. فلذا به اکستنشن متد ها نیاز داریم .
برای اینکه متد AddAuthorName رو داشته باشیم ، باید متد مربوط به اون رو توی کلاس Extensions که خودمون نوشته بودیم ، کمی تغییر بدیم. پس داریم :
اولین تغییری که باید اعمال بشه برای اینکه متد استاتیک نرمالمون به یک اکستنش متد تبدیل بشه ، این هست که باید تایپ هدفمون ( اینجا string ) رو با کلمه کلیدی this به اون پاس بدیم . البته اینجا یکم لاجیک متدمون رو هم دستکاری کردیم که بجای اینکه فقط author رو اضافه کنه ، نتیجه رو هم توی کنسول چاپ کنه.
همونطور که بالا توی تصویر مشاهده میکنید ، متد AddAuthorName بدون مشکل کار میکنه و انگار توی تایپ string وجود داره ( که داره ) ، اما ما خود تایپ استرینگ رو دستکاری نکردیم و صرفا اومدیم اون رو Extend کردیم.
شاید برامون سوال پیش بیاد که متدی که ما تعریف کردیم ، استاتیک بود ولی ما اون رو با سینتکس Instance Methods کال کردیم و مشکلی نبود. طبق چیزی که خود داکیومنت مایکروسافت به اون اشاره میکنه، IL یا همون Intermediate Language میاد و با کمک Compiler کد مارو ترجمه میکنه ، یعنی ما مینویسیم :
"Extension Methods in C#".AddAuthorName("Ahmadreza Mozaffary");
ولی چیزی که بعد از کامپایل اجرا میشه کد زیر هست :
Extensions.AddAuthorName("Extension Methods in C#", "Ahmadreza Mozaffary");
⚠ اما نکته ای که باید حواسمون بهش باشه این هست که ، حتما باید namespace مربوط به کلاس Extensions مون رو توی این فایل ، اضافه کرده باشیم. اما ما میتونیم namespace فایل Extensions مون رو بجای مثلا CustomExtension به System تغییر بدیم ، اینجوری هرجا که ما using System رو استفاده میکنیم ، اکستنشنمون هم دردسترس هست. اما این کار خیلی خطرناکه و ممکنه برامون دردسر درست که یا تداخلی پیش بیاد ، پس Safe و امن نیست :)
توی مقدمه ، راجع به این صحبت کردیم که Extension Method ها ، به خوانایی کدمون کمک میکنن. بالاتر توی متد AddAuthorName این رو دیدیم. یک مثال دیگه اگه بخوایم بزنیم ، فرض کنیم ما یک کد به شکل زیر داریم :
AddToDatabase(GetUserChoice(FindUser(user)));
حالا به کمک اکستنشن متد ها ، کد بالا رو به کد زیر تبدیل میکنیم :
user.FindUser().GetUserChoice().AddToDatabase();
به نظر خودتون کدومشون خوانا تره ؟
حالا اگه از این مباحث بگذریم ، به یک سوال دیگه باید پاسخ بدیم چه موقع باید از اکستنشن متد ها استفاده کرد ؟
اکستنشن متد ها ، کلی مزیت دارن که برخی از اونا رو بررسی کردیم، اما مثل هر فیچر و امکانات دیگه ای ، نباید توی استفاده از اون زیاده روی کنیم و از طرفی، نباید یک نسخه رو برای تمامی نیازمندی ها پیچید! یکی از جاهایی که بهتره از اونا استفاده کرد، وقت هایی هست که ما میخوایم چیزی رو Extend کنیم که برای ما نیست ( یعنی توسط ما نوشته نشده یا به سورس اون دسترسی برای اعمال تغییرات نداریم ) یا وقتی که میخوایم به کلاسمون یک دیپندنسی اضافه کنیم، بدون اینکه کلاسمون به اون وابسته باشه :)
مثلا توی متد مثال انتزاعی بالا ، فرض کنیم میخوایم که متد AddToDatabase وابسته به دیتابیس فعلیمون نباشه و فرضا یدونه connectionString یا DbContext بگیره.
تمامی موارد قابل پیاده سازی توسط اکستنش متد ها روی کلاس ها ، روی اینترفیس ها هم امکان پذیرن. یعنی ما میتونیم با کلمه this یدونه اینترفیس رو به اکستنشن متدمون پاس بدیم.
مزیتی که پاس دادن اینترفیس بجای کلاس داره ، این هست که نه تنها کلاس اصلی ، بلکه تمامی کلاسهایی که اون اینترفیس رو ایمپلمنت کردن هم به اون اکستنشن متدها ، دسترسی دارن ! 😃 چی از این خفن تر ؟
در واقع بجای اینکه تک تک کلاس هایی که یک اینترفیس رو ایمپلمنت کردن Extend کنیم، میایم و اکستنشن متدمونو به کمک اون اینترفیسه مینویسیم و روی تک تک اون کلاسها ، اکستند کردن رو به نوعی انجام میدیم.
چه موقع نباید از اکستنشن متدها استفاده کنیم ؟
توی مثال بالا، ما روی یک Primitive دیتاتایپ عملیات اکستند کردن رو انجام دادیم که صرفا برای بررسی بیشتر و یادگیری راحت تر بود، اما به طور کلی، باید خودمون رو از نوشتن اکستنشن متدهای زیاد و غرق شدن توی اکستند کردن هرچیزی محدود کنیم و فقط و فقط وقتی که یا به سورسِ تایپِ مد نظرمون دسترسی نداریم و یا وقتی که به سورسِ تایپِ مد نظرمون دسترسی داریم ولی نمیخوایم اون رو مودیفای کنیم ، به فکر استفاده از اکستنشن متدها بیوفتیم.
به طور کلی ، اگر امکان این رو داریم که فانکشنالیتی رو مستقیما به تایپمون اضافه کنیم ( حالا یا به عنوان یک متد جدید یا ریفکتور متد موجود ) حتما این کار رو بکنیم و استفاده از اکستنشن متدها رو نادیده بگیریم.
از جمله معروف ترین اکستنشن متدهایی که میتونیم از اونا یاد کنیم ، متدهای LINQ هستن که توی namespaceـی با نام System.Linq در دسترس ما هستن.
سخن پایانی :
من ، احمدرضا مظفری ، از شما کمال تشکر و قدردانی رو بابت مطالعه این مقاله دارم و از شما صمیمانه درخواست میکنم که اگر نکته ای یا انتقاد یا پیشنهادی رو داشتید ، از روش های ارتباطی زیر استفاده کنید :
از طریق آدرس لینکدین من ( کلیک کنید ) یا از بخش کامنت ها ، نظراتتون رو با من درمیون بگذارید .