توسعه و گسترش توابع و کلاسها در ویژوال بیسیک دات نت
در هنگام استفاده از کلاسها در برنامهنویسی، ممکن است برخی مواقع نیاز به کارایی بیشتری از کلاس مورد نظر داشته باشیم. مثلا نیاز به یک تابع اضافه در کلاس داریم که کار به خصوصی که مورد انتظارمون هست رو انجام بده. برای این کار چند راه حل وجود دارد:
یک راه، تغییر سورس کلاس مورد نظر هست. در این روش کاملا مشخصه که باید به سورس این کلاس دسنرسی داشته باشیم، تابع دلخواه رو به سورس اضافه کنیم و این کلاس رو در دات نت دوباره کامپایل کنیم.
خوب، اگه به سورس کلاس دسترسی نداشته باشیم چی؟ و یا در یک تیم برنامه نویسی، اجازه تغییر سورس کلاسهای نوشته شده توسط بخشهای دیگه رو نداشته باشیم، یا کلا این تابع مورد نظر ما اونقدر استفاده به خصوص و شخصی داره که نیازی به وارد کردن اون در ساختار اصلی کلاس نباشه. حالا باید چه کرد؟
اگر به این فکر میکنید که میشه کلاس جدیدی ساخت و از کلاس مورد نظر ارث برد و متدهای جدید رو به اون اضافه کرد، بیخیال بشید. چون از هر کلاسی که نمیشه ارث پذیری داشت. ممکنه جلوی این قابلیت در کل کلاس گرفته شده باشه (NotInheritable) و یا این محدودیت در مورد برخی توابع وجود داشته باشه. خیلی دردسر داره نه؟
یک راه معمول دیگه در برنامهنویسی استفاده از کلاسهای کمکی هست که به صورت Shared در VB.Net ساخته میشه (همون static دز سی شارپ). به این کلاسها معمولا اسم Helper یا Utility گفته میشه چون که نقش کمکی در کدنویسی دارند و ممکن است چندین بار در یک برنامه از اونها استفاده بشه.
برای مثال نیاز به کنترل کردن آدرس ایمیل وارد شده از طرف کاربر سایت هست تا ببینیم این ایمیل درست نوشته شده یا نه؟ برای این کار یک کلاس به اسم AppUtility ایجاد میکنیم و یک تابع به اسم CheckEmail در اون به صورت Shared میسازیم:
Public Class MyUtility
Public Shared Function CheckEmail(ByVal email As String) As Boolean
Dim regex = New Regex("^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$")
Return regex.IsMatch(email)
End Function
End Class
و برای استفاده از این تابع به صورت زیر میتوان عمل کرد:
Dim inputEmail = EmailTextbox.Text
If MyUtility.CheckEmail(inputEmail) Then
'Email is valid..
SubscribeUser()
Else
'Email is invalid
Throw New Exception("Email is invalid")
End If
همونطور که میبینید نیازی به ساختن یک آبجکت جدید از کلاس MyUtility نیست چرا که به صورت Shared تعریف شده. در کلاس MyUtility هر تعدادی از این مدل توابع که نیاز دارید میتوانید بنویسید و از آن هر چند بار که نیاز دارید در طول برنامه، استفاده کنید.
Extension Methods
از ورژن دات نت 3 به بعد، یک قابلیت جدید با عنوان Extension Methods در همین راستا اضافه شد که کار را بسیار راحت تر کرد. با استفاده از Extension Methods شما میتوانید به هر کلاسی قابلیت های جدید رو اضافه کنید بدون اینکه به سورس و حتی ساختار اون کلاس دسترسی داشته باشید و هیچ نیازی به دوباره کامپایل کردن کلاس مورد نظر هم نیست. در واقع شما تابع مورد نظر خودتون رو نوشته و اون رو با این تکنیک وصل میکنید به کلاس مورد نظر.
برای استفاده از اکستنشن متد در VB.Net ابتدا باید یک Module بسازید. سپس باید مشخص کنید که تابع جدید را به چه نوع کلاسی میخواهید اضافه کنید؛ هر کلاسی که بود، باید اولین مقدار پاس شونده به تابع از نوع این کلاس باشد. نمونه کد زیر را ببینید:
Imports System.Runtime.CompilerServices
Public Module MyExtenstionMethods
<Extension()> _
Function CheckEmail(ByVal email As String) As Boolean
Dim regex = New Regex("^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$")
Return regex.IsMatch(email)
End Function
<Extension()> _
Function MathWork(ByVal Number1 As Integer, ByVal Number2 As Integer) As Decimal
Return (Number1 * Number2)/((Number1 + Number2)^2/3)
End Function
End Module
در این مثال دو تابع به صورت Extension Method ساخته شده. تابع اول به اسم CheckEmail یک تابع کمکی برای کلاس String هست. چرا؟ به اولین مقدار پاس داده شده به تابع دقت کنید. متغیر email از نوع string هست. نام انتخاب شده برای email مهم نیست. چیزی که مهمه اینه که تون این متغیر از توع کلاس String هست. پس این تابع به کلاس String اضافه میشود و میتوان از آن استفاده کرد:
همونطور که در شکل میبینید، متغیر mystring از نوع String ساخته شده و امکان استفاده از تابع CheckEmail برای آن فراهم شده است. در واقع در تابع CheckEmail متغیر اول الان در واقع خود mystring میباشد.
و البته مشخص است که ویژوال استودیو در هنگام کدنویسی، توابع اضافه شده را هم به سیستم intellisense خودش اضافه کرده که کار را بسیار راحت میکند. به علامتی که برای توابع اکتنشن استفاده شده است دقت کنید.
تابع دوم هم برای کلاس Integer تعریف میکنیم تا یک عملیات ریاضی را بین دو عدد انجام دهد (زیاد روی فرمول نوشته شده فکر نکنید!). برای همین متغیر اول باید از نوع Integer تعریف شود تا این تابع به صورت خودکار به کلاس Integer اضافه شود. به این تابع میخواهیم یک عدد دیگر هم بفرستیم تا بین 2 عدد این فرمول ریاضی، یک عدد جدید را محاسبه کرده و تحویل دهد. نحوه استفاده از این اکستنشن به صورت زیر هست:
Dim FirstNumber as Integer = 22
ResultTextbox.Text = FirstNumber.MathWork(45)
در این حالت متغیر اول پاس داده شده به اکستنشن، FirstNumber یعنی عدد 20 هست و متغیر دوم هم عدد 45 میباشد. دقت کنید که Extension Method نوشته شده همواره تعداد ورودی های آن از تعداد متغیرهایی که باید هنگام کدنویسی به آن پاس دهید یکی بیشتر هست. چون متغیر اول پاس داده شده، همون آبجکتی هست که این اکستنشن رو برای کلاسش نوشتیم.
مثالی که در ابتدا با روش Helper Class نوشته شده بود را میتوان به صورت زیر نوشت:
If EmailTextbox.Text.CheckEmail Then
'Email is valid..
SubscribeUser()
Else
'Email is invalid
Throw New Exception("Email is invalid")
End If
چند نکته بسیار مهم وجود داره که اگر رعایت نکنید،ممکن هست Extension Method های شما کار نکند و برای زمان زیادی سر کار باشید:
حتما از Public Module استفاده کنید. اگر کلمه Public رو فراموش کنید، Extension Method شما کار نخواهد کزد.
نکته بعدی اینکه Imports System.Runtime.CompilerServices فراموش نشود و برای هر تابعی که میخواهید نقش Extension را بازی کند از فیلتر <Extension> همونطور که در نمونه کد میبینید استفاده کنید.
و در نهایت، بعد از نوشتن Module همواره حواستون باشه که ابتدا این فایل رو کامپایک کرده باشید و بعدا به سراغ استفاده از اون در قسمتهای دیگه مد بروید. اگر این کار را نکنید، ویژوال استودیو توابع اکستنشن شما رو در intellisense نمیاره. برای کامپایل کردن در ویژوال استودیو از منو Build و بعد از اون Build class name استفاده کنید.
*این مطالب از خودم میباشد! اگر در اون مورد اشتباهی میبینید، ممنون میشم که اعلام کنید و استفاده از این مطلب آزاد هست و اگر دوست دارید با انصاف باشید، منبع رو هم ذکر کنید.