کلمات کلیدی شناسه های از پیش تعریف شده و رزرو شده ای هستند که معانی خاصی برای کامپایلر دارند. آنها نمی توانند به عنوان شناسه در برنامه شما استفاده شوند مگر اینکه @ را به عنوان پیشوند درج کنند. برای مثال، if@ یک شناسه معتبر است، اما if نیست، زیرا if یک کلمه کلیدی است.
کلمه کلیدی Readonly در سی شارپ
کلمه کلیدی readonly یک modifier است که می تواند در چهار مورد زیر استفاده شود:
1- در اعلان فیلد، readonly نشان می دهد که تخصیص به فیلد فقط می تواند به عنوان بخشی از اعلان یا در سازنده ای در همان کلاس رخ دهد. یک فیلد readonly را می توان چندین بار در اعلان فیلد و سازنده تخصیص داد. پس از خروج سازنده نمی توان یک فیلد readonly اختصاص داد. این قانون مفاهیم مختلفی برای انواع value و انواع reference دارد:
*** از آنجایی که انواع value مستقیماً حاوی داده های خود هستند، فیلدی که یک نوع مقدار readonly است غیرقابل تغییر است.
*** از آنجایی که انواع reference حاوی ارجاع به داده های خود هستند، فیلدی که یک نوع مرجع readonly است باید همیشه به همان شیء اشاره کند. آن شیء تغییرناپذیر نیست. تعیین کننده readonly از جایگزینی فیلد با نمونه ای متفاوت از نوع reference جلوگیری می کند. با این حال، تعیین کننده مانع از اصلاح داده های نمونه فیلد از طریق فیلد readonly نمی شود.
2- در تعریف نوع ساختار فقط خواندنی (readonly)، readonly نشان می دهد که نوع ساختار تغییرناپذیر است.
3- در یک اعلان عضو نمونه در یک نوع ساختار، readonly نشان می دهد که یک عضو نمونه وضعیت و یا حالت ساختار را تغییر نمی دهد.
4- در روش بازگشتی فقط خواندنی ref، اصلاح کننده فقط خواندنی نشان می دهد که متد یک reference را برمی گرداند و نوشتن در آن مرجع مجاز نیست.
در ادامه مثالی از کاربرد فیلد readonly در سی شارپ نشان داده شده است. در این مثال، مقدار فیلد year را نمی توان در متد ChangeYear تغییر داد، حتی اگر مقداری در سازنده کلاس به آن اختصاص داده شده باشد:
فقط در موارد زیر می توانید مقداری را به یک فیلد فقط خواندنی اختصاص دهید:
1- هنگامی که متغیر در هنگام تعریف مقداردهی اولیه می شود، به عنوان مثال:
2- در سازنده نمونه کلاس که حاوی تعریف فیلد نمونه است.
3- در سازنده استاتیک کلاس که حاوی تعریف فیلد استاتیک است.
این سازنده ها همچنین تنها مواردی هستند که در آن ها ارسال یک فیلد فقط خواندنی به عنوان پارامتر out یا ref معتبر است.
کلمه کلیدی فقط خواندنی (readonly keyword) با کلمه کلیدی const متفاوت است. یک فیلد const فقط می تواند در تعریف فیلد مقداردهی اولیه شود. یک فیلد فقط خواندنی را می توان چندین بار در تعریف فیلد و در هر سازنده ای اختصاص داد. بنابراین، فیلدهای فقط خواندنی بسته به سازنده مورد استفاده می توانند مقادیر متفاوتی داشته باشند. همچنین، در حالی که یک فیلد const یک ثابت زمان کامپایل است، فیلد فقط خواندنی می تواند برای ثابت های زمان اجرا مانند مثال زیر استفاده شود.
خروجی قطعه کد بالا در ادامه نشان داده شده است.
در مثال بالا، اگر از عبارتی مانند مثال زیر استفاده کنید پیغام خطای کامپایلر (یک فیلد فقط خواندنی را نمی توان به آن اختصاص داد (به جز در سازنده یا مقداردهی اولیه متغیر)) را دریافت خواهید کرد.
کلمه کلیدی Init در سی شارپ
از سی شارپ ورژن 9 به بعد، کلمه کلیدی init یک متد Accessor را در یک property یا indexer تعریف می کند. یکinit-only setter یک مقدار را به property یا عنصر indexer فقط در حین ساخت شیء اختصاص می دهد. مثال زیر هم get و هم یک init accessor را برای یک ویژگی به نام Seconds تعریف می کند که از یک فیلد خصوصی به نام _seconds برای پشتیبانی از مقدار property استفاده می کند.
اغلب،init accessor از یک عبارت واحد تشکیل شده است که مانند مثال قبلی، یک مقدار را اختصاص می دهد. می توانید init accessor را به عنوان یک عضو با بدنه پیاده سازی کنید. مثال زیر هر دو عبارت get و init accessor را به صورت اعضایی که در بدنه بیان می شوند را پیاده سازی می کند.
در حالت های ساده که در آن get و init accessors مربوط به یک property به جز ست کردن یا بازیابی یک مقدار در یک فیلد پشتیبانی از نوع خصوصی، هیچ عملیات دیگری را انجام نمی دهند، می توانید از پشتیبانی کامپایلر #C برای property های پیاده سازی شده خودکار(auto-implemented property) بهره ببرید. مثال زیر Hours را به عنوان یک auto-implemented property پیاده سازی می کند.
مکانیسم های اساسی برای ساخت داده های تغییرناپذیر در سی شارپ از ورژن 1.0 تغییر نکرده است. آنها به دو شکل زیرباقی مانده اند:
1- تعریف فیلدها به عنوان فقط خواندنی (readonly)
2- تعریف property هایی که فقط حاوی یک get accessor هستند.
این مکانیسم ها در اجازه ساخت داده های تغییرناپذیر مؤثر هستند، اما توسعه دهندگان باید بین سهولت استفاده و تغییر ناپذیری یکی را انتخاب کنند. در مثال زیر شیء تغییرناپذیر ساده Pointبه دو برابر تعداد خط کد برای پشتیبانی از ایجاد نیاز دارد زیرا باید نوع را مشخص کند. به عبارت دیگر، هر چه نوع بزرگتر باشد، هزینه بیشتر است:
init accessor با اجازه دادن به فراخوانده برای تغییر و جهش اعضا در هنگام ساخت، اشیای تغییرناپذیر را انعطاف پذیرتر می کند. این بدان معناست که ویژگی های تغییرناپذیر شیء می توانند در مقداردهی اولیه شیء مشارکت داشته باشند و در نتیجه نیاز به سازنده در نوع را برطرف می کند. نوع Point اکنون به سادگی زیر است:
سپس مصرف کننده می تواند از مقداردهی اولیه شی برای ایجاد شی استفاده کند.
کلمه کلیدی Override در سی شارپ
کلمه کلیدی override برای گسترش یا اصلاح پیاده سازی virtual یک method، property، indexer یا event ارثی مورد نیاز است. در مثال زیر، کلاس Square باید یک پیاده سازی بازنویسی شده از GetArea ارائه کند، زیرا GetArea از کلاس Shape به ارث رسیده است.
خروجی قطعه کد بالا در ادامه نشان داده شده است.
یک متد override پیاده سازی جدیدی از متد به ارث رسیده از کلاس پایه (base class) را ارائه می دهد. متدی که با استفاده از کلمه تعریف override بازنویسی می شود، به عنوان متد پایه بازنویسی شده (overridden base method) شناخته می شود. یک override method باید امضای یکسانی مشابه با overridden base method داشته باشد. با آغاز C#ورژن 9، متدهای overrideاز انواع بازگشتی covariant پشتیبانی می کنند. به طور خاص، نوع برگشتی یک متد override می تواند از نوع برگشتی روش پایه مربوطه مشتق شود. در سی شارپ 8.0 و نسخه های قبلی، انواع برگشتی یک متد override و overridden base method باید یکسان باشند. در استفاده از override نکات زیر را در نظر بگیرید.
*** نمی توان یک متد غیر virtual یا استاتیک را بازنویسی کرد. overridden base method باید virtual یا بازنویسی شده باشد.
*** یک کلمه کلیدی از نوع override نمی تواند دسترسی به متد virtual را تغییر دهد. هم متد override و هم متد virtual باید تعریف کننده سطح دسترسی یکسانی داشته باشند.
*** نمی توانید از کلمات کلیدی new ، static یا virtual برای اصلاح و تغییر یک متد overrideاستفاده کنید.
*** تعریف ویژگی بازنویسی شده (overriding property) باید دقیقاً همان access modifier ، نوع و نام ویژگی موروثی را مشخص کند. overridden property میبایست virtual، abstract و یا override باشد.
کلمه کلیدی Virtual در سی شارپ
کلمه کلیدی virtual چیست؟ قبل از اینکه مستقیماً به دیدگاه سی شارپ بپردازیم، درک یا مرور مفهوم وراثت، کلیدواژه های overriding و virtual در دنیای برنامه نویسی شی گرا مهم است.
Method Overriding یک مفهوم مهم در OOPs است که به مفهوم Inheritance یا وراثت نزدیک است. هنگامی که یک متد کلاس فرزند، متد کلاس والد با همان نام، پارامترها و نوع بازگشتی را بازنویسی می کند، این فرایند method overriding نامیده می شود. کلمه کلیدی virtual نشانه ای برای کامپایلر است که ممکن است یک متد در کلاس های مشتق شده بازنویسی شده باشد.
از دیدگاه #C، از کلمه کلیدی virtual برای تغییر تعریف هر property ، method یا event استفاده می شود تا اجازه بازنویسی شدن یا overriding در کلاس مشتق شده را بدهد. به زبان ساده، کلمه کلیدی virtual مفهوم method overriding را در سی شارپ پیاده سازی می کند.
تفاوت اساسی بین overloading و overriding در این است که overloading یک مکانیسم زمان کامپایل است، در حالی که overriding در زمان اجرا وارد عمل می شود. یک کلمه کلیدی virtual در زمان اجرا وارد عمل می شود، بنابراین مفهوم method overriding را پیاده سازی می کند.
هنگامی که هر متد یا ویژگی virtual فراخوانی می شود یا به آن دسترسی پیدا می شود، کامپایلر عضو بازنویسی شده را بررسی می کند. اگر یک overriding member پیدا شد که فراخوانی می شود. اگر هیچ موردی یافت نشد، متد یا ویژگی اصلی فراخوانی می شود.
همانطور که گفته شد کلمه کلیدی virtual برای تغییر یک متد، property ، indexer یا تعریف event استفاده می شود و اجازه می دهد که آن در یک کلاس مشتق شده (derived class) بازنویسی (override) شود. به عنوان مثال، این متد می تواند توسط هر کلاسی که آن را به ارث می برد، بازنویسی شود:
پیاده سازی یک عضو virtual را می توان توسط یک عضو بازنویسی شده (overriding member) در یک کلاس مشتق شده (derived class) تغییر داد.
هنگامی که یک متد virtual فراخوانی می شود، نوع زمان اجرا شیء برای یک عضو بازنویسی شده (overriding member) بررسی می شود. عضو بازنویسی شده در مشتق شده ترین کلاس فراخوانی می شود که ممکن است عضو اصلی باشد، اگر هیچ کلاس مشتق شده ای عضو را بازنویسی نکرده باشد.
به طور پیش فرض، متد ها غیر virtual هستند. شما نمی توانید یک متد غیر virtual را بازنویسی کنید. همچنین نمی توانید از کلمه کلیدی virtual با کلمات کلیدی static ، abstract ، private یا override استفاده کنید. مثال زیر یک ویژگی virtual را نشان می دهد:
virtual properties مانند متدهای virtual عمل می کنند، به جز تفاوت های موجود در نحوه اعلان و فراخوان. همچنین لازم است بدانیم که:
1- استفاده از تعریف کننده virtual روی یک ویژگی استاتیک یک خطا است.
2- یک ویژگی ارثی virtual را می توان در یک کلاس مشتق شده با اضافه کردن یک تعریف ویژگی که از تعریف کننده override استفاده می کند، بازنویسی کرد.
کلمه کلیدی Sealed در سی شارپ
کلمه کلیدی sealed هنگامی که به یک کلاس اعمال می شود، از ارث بری سایر کلاس ها از آن جلوگیری می کند. در مثال زیر، کلاس B از کلاس A ارث می برد، اما هیچ کلاسی نمی تواند از کلاس B ارث ببرد.
همچنین می توانید از sealed modifier برای یک متد یا ویژگی که یک متد virtual یا ویژگی در کلاس پایه را بازنویسی (override) می کند استفاده کنید. این به شما امکان می دهد تا به کلاس ها اجازه دهید از کلاس شما مشتق شوند و از بازنویسی متدها یا ویژگی های virtual خاص توسط این کلاس ها جلوگیری می کند.
برای تعیین seal کردن یک کلاس، متد یا property، به طور کلی باید دو نکته زیر را در نظر بگیرید:
1- مزایای بالقوه ای که ممکن است استخراج کلاس ها از طریق توانایی سفارشی کردن کلاس شما به دست آورد.
2- قابلیت اینکه آیا این احتمال وجود دارد که استخراج کلاس ها می تواند کلاس های شما را به گونه ای تغییر دهد که دیگر به درستی یا مطابق انتظار کار نکنند.
در مثال زیر، Z از Y ارث می برد اما Z نمی تواند تابع virtual F را که در X تعریف شده و در Y مهر و موم شده است، بازنویسی کند.
هنگامی که متدها یا property های جدیدی را در یک کلاس تعریف می کنید، می توانید با عدم اعلام virtual (virtual) بودن کلاس ها، از بازنویسی آنها توسط کلاس های مشتق جلوگیری کنید.
استفاده از کلمه کلیدی abstract با یک کلاس مهر و موم شده (sealed class) یک خطا است، زیرا یک کلاس انتزاعی باید توسط کلاسی به ارث برده شود که پیاده سازی متدها یا ویژگی های انتزاعی را ارائه می دهد.
هنگامی که sealed modifier به یک متد یا ویژگی اعمال می شود، باید همیشه با override استفاده شود.
از آنجا که ساختارها به طور ضمنی مهر و موم شده اند، نمی توان آنها را به ارث برد.
خروجی قطعه کد بالا در ادامه نشان داده شده است.
در مثال قبلی، ممکن بود سعی کنید با استفاده از عبارت زیر از کلاس sealed ارث بری کنید:
class MyDerivedC: SealedClass {} // Error
که نتیجه آن پیغام خطای زیر است:
'MyDerivedC': cannot derive from sealed type 'SealedClass'