0% found this document useful (0 votes)
43 views269 pages

C# - Programming

Uploaded by

mahya111h
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
43 views269 pages

C# - Programming

Uploaded by

mahya111h
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 269

‫پیشرفتهﺸﺮﻓﺘﻪ‬

‫نویسیزي ﭘﯿ‬
‫برنامهﻪ ﺳﺎ‬
‫سﺮﻧﺎﻣ‬ ‫جزوه در‬
‫سﺑ‬ ‫ﺟ ﺰوه د ر‬
‫آموزش ‪C#‬‬

‫‪Application‬ﯽ ‪C#‬‬
‫‪Console‬‬ ‫محیطﺮﻧﺎﻣﻪ ﻧﻮﯾﺴ‬
‫در ﺑ‬

‫محمد عزیزی‬
‫ﻧﺮم اﻓﺰار ﮐﺎﻣﭙﯿﻮﺗﺮ‬
‫‪[email protected]‬‬
‫‪MaziziUni.blogfa.com‬‬

‫آموزشکده فنی و حرفه ای پسران‬

‫‪1‬‬
‫فهرست موضوعی‬

‫مبانی زبان سی شارپ‬

‫سی شارپ چیست؟‬

‫دات نت فریم ورک (‪ ).NET Framework‬چیست؟‬

‫ویژوال استودیو‬

‫دانلود و نصب ویژوال استودیو‬

‫قانونی کردن ویژوال استودیو‬

‫گردشی در ویژوال استودیو‬

‫تغییر ظاهر ویژوال استودیو‬

‫ساخت یک برنامه ساده‬

‫استفاده از ‪IntelliSense‬‬

‫رفع خطاها‬

‫توضیحات‬

‫کاراکترهای کنترلی‬

‫عالمت @‬

‫متغیرها‬

‫انواع ساده‬

‫استفاده از متغیرها‬

‫ثابت ها‬

‫تبدیل ضمنی‬

‫تبدیل صریح‬

‫تبدیل با استفاده از کالس ‪Convert‬‬

‫عبارات و عملگرها‬

‫عملگرهای ریاضی‬

‫عملگرهای تخصیصی ( جایگزینی)‬

‫عملگرهای مقایسه ای‬

‫عملگرهای منطقی‬
‫‪2‬‬
‫عملگرهای بیتی‬

‫تقدم عملگرها‬

‫گرفتن ورودی از کاربر‬

‫ساختارهای تصمیم‬

‫دستور ‪if‬‬

‫دستور ‪else…if‬‬

‫عملگر شرطی‬

‫دستور ‪ if‬چندگانه‬

‫دستور ‪ if‬تو در تو‬

‫استفاده از عملگرهای منطقی‬

‫دستور ‪Switch‬‬

‫تکرار‬

‫حلقه ‪While‬‬

‫حلقه ‪do while‬‬

‫حلقه ‪for‬‬

‫حلقه های تو در تو (‪)Nested Loops‬‬

‫خارج شدن از حلقه با استفاده از ‪ break‬و ‪continue‬‬

‫آرایه ها‬

‫حلقه ‪foreach‬‬

‫آرایه های چند بعدی‬

‫آرایه دندانه دار‬

‫متد‬

‫مقدار برگشتی از یک متد‬

‫پارامترها و آرگومان ها‬

‫نامیدن آرگومان ها‬

‫ارسال آرگومان ها به روش ارجاع‬

‫پارامترهای ‪out‬‬

‫ارسال آرایه به عنوان آرگومان‬

‫کلمه کلیدی ‪params‬‬

‫‪3‬‬
‫محدوده متغیر‬

‫پارامترهای اختیاری‬

‫سربارگذاری متدها‬

‫بازگشت (‪)Recursion‬‬

‫نماینده ها(‪)Delegates‬‬

‫آرگومان های خط فرمان (‪)Command Line Arguments‬‬

‫شمارش (‪)Enumeration‬‬

‫تبدیل انواع شمارشی‬

‫ساختار (‪)Struct‬‬

‫برنامه نویسی شیء گرا (‪) Object Oriented Programming‬‬

‫کالس‬

‫سازنده ها (‪)Constructors‬‬

‫مخرب ها (‪)Destructors‬‬

‫فیلدهای فقط – خواندنی‬

‫سطح دسترسی‬

‫کپسوله کردن (‪)Encapsulation‬‬

‫خواص (‪)Properties‬‬

‫فضای نام‬

‫تفاوت ساختار و کالس‬

‫کتابخانه کالس‬

‫وراثت‬

‫سطح دسترسی ‪Protect‬‬

‫اعضای ‪Static‬‬

‫کالس ‪Static‬‬

‫متدهای مجازی‬

‫کالس آبجکت(‪)System.Object Class‬‬

‫‪ Boxing‬و ‪Unboxing‬‬

‫ترکیب (‪)Containment‬‬

‫سربارگذاری عملگرها‬

‫‪4‬‬
‫عملگر ‪is‬‬

‫رابط ها (‪)Interfaces‬‬

‫کالسهای انتزاعی (‪)Abstract Class‬‬

‫کالس مهر و موم شده (‪)Sealed Class‬‬

‫کالس تکه تکه (‪)partial class‬‬

‫چند ریختی (‪)Polymorphism‬‬

‫عملگر ‪as‬‬

‫سربارگذاری تبدیل ها‬

‫ایجاد آرایه ای از کالسها‬

‫ایندکسر (‪)Indexer‬‬

‫‪String Interpolation‬‬

‫مدیریت استثناءها و خطایابی‬

‫استثناءهای اداره نشده‬

‫دستورات ‪ try‬و ‪catch‬‬

‫استفاده از بلوک ‪finally‬‬

‫ایجاد استثناء‬

‫خواص ‪Exception‬‬

‫تعریف یک استثناء توسط کاربر‬

‫اشکال زدایی توسط ویژوال استودیو‬

‫نقطه انفصال (‪)Breakpoints‬‬

‫قدم زدن در میان کدها‬

‫به دست آوردن مقادیر متغیرها‬

‫کلکسیون ها (‪) Collections‬‬

‫کالس ‪ArrayList‬‬

‫ایجاد یک کلکسیون‬

‫ساخت دیکشنری‬

‫‪Hashtable‬‬

‫انواع ‪ Enumerator‬و ‪Enumerable‬‬

‫رابط های ‪ IEnumerator‬و ‪IEnumerable‬‬

‫‪5‬‬
‫پیمایشگر (‪)Iterator‬‬

‫جنریک ها (‪)Generics‬‬

‫متدهای جنریک‬

‫کالس جنریک‬

‫محدودیت نوع (‪)Type Constraints‬‬

‫کلکسیون عمومی (‪)Generic Collection‬‬

‫‪Object Initializer‬‬

‫انواع تهی‬

‫عملگر (??) ‪null Coalescing‬‬

‫رویداد ها (‪)Events‬‬

‫متدهای بی نام (‪)Anonymous Methods‬‬

‫نوع استنباطی (‪)Type Inference‬‬

‫انواع بی نام (‪)Anonymous Types‬‬

‫متدهای توسعه یافته‬

‫عبارات المبدا (‪)Lambda expressions‬‬

‫‪Expression-Bodied Members‬‬

‫استفاده از کالس های استاتیک در فضای نام‬

‫مقدار دهی اولیه به خصوصیات خودکار‬

‫فیلتر استثنائات‬

‫دستور ‪using‬‬

‫مخفی کردن متد (‪)Method Hiding‬‬

‫‪ Tuple‬چیست‬

‫توابع محلی (‪)Local Functions‬‬

‫اشیاء تغییر ناپذیر (‪)Immutable Object‬‬

‫‪6‬‬
‫آموزش سی شارپ‬
‫دسته بندی‬ ‫•‬

‫‪C#.NET‬‬ ‫‪o‬‬

‫‪JAVA o‬‬
‫‪C++‬‬ ‫‪o‬‬

‫‪PHP‬‬ ‫‪o‬‬

‫‪PYTHON o‬‬
‫‪Kotli o‬‬

‫سی شارپ چیست؟مشکالت برنامه نویسی را اینجا مطرح کنید‬

‫سی شارپ (‪ :)C#‬یک زبان برنامهنویسی شیء گراست‪ ،‬که توسط شرکت مایکروسافت ساخته شده و ترکیبی از قابلیتهای خوب ‪ C++‬و ‪ JAVA‬است‪ .‬اگر‬
‫با این دو زبان آشنایی دارید‪ ،‬این شانس را دارید که زبان ‪ C#‬را راحت یاد بگیرید‪ .‬این زبان به قدری راحت است که هم کسانی که قبالً برنامهنویسی نکردهاند و‬
‫هم دانش آموزان میتوانند راحت آن را یاد بگیرند‪.‬‬
‫از سی شارپ‪ ،‬میتوان برای ساخت برنامههای تحت ویندوز‪ ،‬تحت وب‪ ،‬وب سرویسها‪ ،‬برنامههای موبایل و بازیها استفاده کرد‪ .‬میتوان به جای واژه ویژوال‬
‫سی شارپ از کلمه سی شارپ استفاده کرد‪ ،‬اما ویژوال سی شارپ به معنای استفاده همزمان از سی شارپ و محیط گرافیکی ویژوال استودیو میباشد‪ .‬این زبان‬
‫برنامهنویسی تنها زبانی است که مخصوصاً برای دات نت فریم ورک طراحی شده است‪.‬‬
‫سی شارپ از کتابخانه کالس دات نت که شامل مجموعه بزرگی از اجزاء از قبل ساخته شده است‪ ،‬استفاده میکند‪ .‬این اجزاء به ساخت هر چه سریعتر برنامهها‬
‫کمک میکنند‪ .‬سی شارپ یک برنامه بسیار قدرتمند و شیء گرا است و با آن میتوان برنامههایی با قابلیت مدیریت بیشتر و درک آسان ایجاد کرد‪ .‬ساختار این‬
‫زبان نسبت به زبانهای دیگر بسیار آسان و قابل فهم است‪.‬‬
‫برای اجرای یک برنامه سی شارپ ابتدا باید داتنت فریمورک نصب شود‪ .‬سی شارپ یکی از زبانهایی است که از تکنولوژیهای دیگر دات نت مانند‪،‬‬
‫‪ Silverlight، ASP.NET‬و ‪ XNA‬پشتیبانی می کند‪ .‬همچنین یک محیط توسعه یکپارچه دارد که آن نیز به نوبه خود دارای ابزارهای مفیدی است که به‬
‫شما در کدنویسی کمک میکند‪.‬‬

‫تاریخچه زبان سی شارپ‬

‫با ظهور ‪ C# 7.3‬قابلیتهای جدیدی به این زبان اضافه شد که به شما امکان میدهند که برنامههایی بهینه تر و پربار تر با کدنویسی کمتر بنویسید‪ .‬حال که‬
‫اسم نسخه ‪ 7.3‬سی شارپ به میان آمد‪ ،‬بهتر است که با نسخههای مختلف این زبان‪ ،‬از ابتدا تاکنون که در جدول زیر آمده است‪ ،‬آشنا شوید‪:‬‬

‫‪7‬‬
‫تاریخ ارائه‬ ‫نسخه‪Visual Studio‬‬ ‫نسخه سی شارپ نسخه‪.NET Framework‬‬

‫‪January 2002‬‬ ‫‪Visual Studio.NET 2002‬‬ ‫‪.NET Framework 1.0‬‬ ‫‪C# 1.0‬‬

‫‪April 2003‬‬ ‫‪Visual Studio.NET 2003‬‬ ‫‪.NET Framework 1.1‬‬ ‫‪C# 1.1‬‬

‫‪November 2005‬‬ ‫‪Visual Studio 2005‬‬ ‫‪.NET Framework 2.0‬‬ ‫‪C# 2.0‬‬

‫‪November 2007‬‬ ‫‪Visual Studio 2008‬‬ ‫‪.NET Framework 3.0\3.5‬‬ ‫‪C# 3.0‬‬

‫‪April 2010‬‬ ‫‪Visual Studio 2010‬‬ ‫‪.NET Framework 4.0‬‬ ‫‪C# 4.0‬‬

‫‪August 2012‬‬ ‫‪Visual Studio 2012/2013‬‬ ‫‪.NET Framework 4.5‬‬ ‫‪C# 5.0‬‬

‫‪July 2015‬‬ ‫‪Visual Studio 2015‬‬ ‫‪.NET Framework 4.6‬‬ ‫‪C# 6.0‬‬

‫‪March 2017‬‬ ‫‪Visual Studio 2017‬‬ ‫‪.NET Framework 4.6.2‬‬ ‫‪C# 7.0‬‬

‫)‪August 2017 Visual Studio 2017 (version 15.3‬‬ ‫‪.NET Framework 4.6.2‬‬ ‫‪C# 7.1‬‬

‫)‪November 2017 Visual Studio 2017 (version 15.5‬‬ ‫‪.NET Framework 4.7.1‬‬ ‫‪C# 7.2‬‬

‫)‪May 2018 Visual Studio 2017 (version 15.7‬‬ ‫‪.NET Framework 4.7.2‬‬ ‫‪C# 7.3‬‬

‫‪September 2019 Visual Studio 2019 (version 16.3) .NET Framework 4.8, .NET Core 3.0‬‬ ‫‪C# 8.0‬‬

‫دلیل پیدایش زبان سی شارپ‬

‫دلیل پیدایش این زبان بر طبق دانشنامه ‪ wikipedia‬بدین شرح است که‪:‬‬
‫در سال ‪ ،1999‬شرکت ‪ Sun Microsystems‬اجازه استفاده از زبان برنامهنویسی ‪ JAVA‬را در اختیار ‪ Microsoft‬قرار داد تا در سیستم عامل خود از آن‬
‫استفاده کند‪ .‬جاوا در اصل به هیچ سیستم عاملی وابسته نبود‪ ،‬ولی مایکروسافت برخی از مفاد قرارداد را زیر پا گذاشت و قابلیت مستقل از سیستم عامل بودن جاوا‬
‫را از آن برداشت‪ .‬شرکت ‪ Sun Microsystems‬پروندهای علیه مایکروسافت درست کرد و مایکروسافت مجبور شد تا زبان شیءگرای جدیدی با کامپایلر‬
‫جدید که به ‪ C++‬شبیه بود را درست کند‪.‬‬
‫آندرس هلزبرگ (‪ )Anders Hejlsberg‬سرپرستی و مدیریت این پروژه را بر عهده گرفت و گروهی را برای طراحی زبانی جدید تشکیل داد و نام آن را‬
‫‪ Cool‬گذاشت‪ .‬مایکروسافت در نظر داشت‪ ،‬اسم این زبان را تا آخر ‪ Cool‬قرار دهد‪ ،‬ولی به دلیل مناسب نبودن برای اهداف تجاری‪ ،‬این کار را نکرد‪ .‬در ارائه و‬
‫معرفی رسمی چارچوب داتنت در سال ‪ 2000‬این زبان به سی شارپ تغییر نام یافت‪.‬‬
‫سی شارپ به طور دائم توسط مایکروسافت بهروز شده و ویژگیهای جدیدی به آن اضافه میشود و یکی از بهترین زبانهای برنامهنویسی دات نت است‪.‬‬

‫‪8‬‬
‫دات نت فریم ورک (‪ ).NET Framework‬چیست؟‬

‫‪ .NET Framework‬ی ک چارچوب است که توسط شرکت مایکروسافت برای توسعه انواع نرم افزارها علی الخصوص ویندوز طراحی شد‪.NET .‬‬
‫‪ Framework‬همچنین می تواند برای توسعه نرم افزارهای تحت وب مورد استفاده قرار بگیرد‪ .‬تا کنون چندین نسخه از ‪ .NET Framework‬انتشار یافته‬
‫که هر بار قابلیتهای جدیدی به آن اضافه شده است‪.‬‬
‫‪ .NET Framework‬شامل کتابخانه کالس محیط کاری ()‪ )Framework Class Library (FCL‬که در بر گیرنده کالسها‪ ،‬ساختارها‪ ،‬دادههای‬
‫شمارشی و… میباشد‪ .‬مهمترین قسمت ‪ .NET Framework‬زبان مشترک زمان اجرا (‪ ))Runtime (CLR Language Common‬است که‬
‫محیطی را فراهم میآورد که برنامهها در آن اجرا شوند‪ .‬این چارچوب ما را قادر میسازد که برنامههایی که تحت آن نوشته شدهاند اعم از ‪Visual‬‬
‫‪ C#.Net،Basic.Net‬و ‪ C++‬را بهتر درک کنیم‪ .‬کدهایی که تحت ‪ CLR‬و دات نت اجرا میشوند‪ ،‬کدهای مدیریت شده نامیده میشوند‪ ،‬چون ‪CLR‬‬
‫جنبههای مختلف نرم افزار را در زمان اجرا مدیریت میکند‪.‬‬
‫در زمان کامپایل کدها به زبان مشترک میانی ()‪ )Common Intermediate Language (CIL‬که نزدیک و تقریباً شبیه به زبان اسمبلی است‪ ،‬ترجمه‬
‫میشوند‪ .‬ما باید کدهایمان را به این زبان ترجمه کنیم چون فقط این زبان برای دات نت قابل فهم است‪ .‬برای مثال کدهای ‪ C#‬و ‪ Visual Basic.Net‬هر‬
‫دو به زبان مشترک میانی ترجمه میشوند‪ .‬به همین دلیل است که برنامههای مختلف در دات نت که با زبانهای متفاوتی نوشته شدهاند‪ ،‬میتوانند با هم ارتباط‬
‫برقرار کنند‪.‬‬
‫اگر یک زبان سازگار با دات نت میخواهید‪ ،‬باید یک کامپایلر ایجاد کنید که کدهای شما را به زبان میانی ترجمه کند‪ .‬کدهای ترجمه شده توسط ‪ IL‬در یک فایل‬
‫اسمبلی مانند ‪ .exe‬یا ‪ .dll‬ذخیره میشوند‪.‬کدهای ترجمه شده به زبان میانی به کامپایلر فقط در زمان ()‪ )Just – In – Time (JIT‬منتقل میشوند‪ .‬این‬
‫کا مپایلر در لحظه فقط کدهایی را که برنامه در آن زمان نیاز دارد‪ ،‬به زبان ماشین ترجمه میکند‪ .‬در زیر نحوه تبدیل کدهای سی شارپ به یک برنامه اجرایی به‬
‫طور خالصه آمده است‪:‬‬

‫برنامه نویس برنامه خود را با یک زبان دات نت مانند سی شارپ مینویسد‪.‬‬ ‫‪.1‬‬
‫کدهای سی شارپ به وسیله کامپایلر به کدهای معادل آن در زبان میانی تبدیل میشوند‪.‬‬ ‫‪.2‬‬
‫کدهای زبان میانی در یک فایل اسمبلی ذخیره میشوند‪.‬‬ ‫‪.3‬‬
‫وقتی برنامه اجرا میشود کامپایلر ‪ JIT‬کدهای زبان میانی را در لحظه به کدهایی که برای کامپیوتر قابل خواندن باشند (‪ )Native Code‬تبدیل‬ ‫‪.4‬‬
‫میکند‪.‬‬

‫دات نت ویژگی دیگری به نام سیستم نوع مشترک ()‪ )Common Type System (CTS‬نیز دارد که بخشی از ‪ CLR‬است و نقشهای است برای‬
‫معادلسازی انواع دادهها در دات نت‪ .‬با ‪ CTS‬نوع ‪ int‬در سی شارپ و نوع ‪ Integer‬در ویژوال بیسیک یکسان هستند‪ ،‬چون هر دو از نوع ‪System.Int32‬‬
‫مشتق میشوند‪ .‬پاک کردن خانههای بالاستفاده حافظه در یک فایل (‪ )Garbage collection‬یکی دیگر از ویژگیهای دات نت فریم ورک است‪ .‬هنگامی‬
‫که از منابعی‪ ،‬زیاد استفاده نشود دات نت فریم ورک حافظه استفاده شده توسط برنامه را آزاد میکند‬

‫ویژوال استودیو‬

‫ویژوال استودیو (‪ )Visual Studio‬محیط توسعه یکپارچهای است‪ ،‬که دارای ابزارهایی برای کمک به شما برای توسعه برنامههای سی شارپ و دات نت‬
‫میباشد‪ .‬شما میتوانید یک برنامه سی شارپ را با استفاده از برنامه ‪ notepad‬یا هر برنامه ویرایشگر متن دیگر بنویسید و با استفاده از کامپایلر سی شارپ از آن‬
‫استفاده کنید‪ ،‬اما این کار بسیار سخت است چون اگر برنامه شما دارای خطا باشد خطایابی آن سخت میشود‪ .‬توجه کنید که کلمه ویژوال استودیو هم به ویژوال‬
‫استودیو و هم به ویژوال سی شارپ اشاره دارد‪ .‬توصیه میکنیم که از محیط ویژوال استودیو برای ساخت برنامه استفاده کنید چون این محیط دارای ویژگیهای‬
‫‪9‬‬
‫زیادی برای کمک به شما جهت توسعه برنامههای سی شارپ میباشد‪ .‬تعداد زیادی از پردازشها که وقت شما را هدر میدهند به صورت خودکار توسط ویژوال‬
‫استودیو انجام میشوند‪.‬‬
‫یکی از این ویژگیها اینتلی سنس (‪ )Intellisense‬است که شما را در تایپ سریع کدهایتان کمک میکند‪ .‬یکی دیگر از ویژگیهای اضافه شده‪break ،‬‬
‫‪ point‬است که به شما اجازه میدهد در طول اجرای برنامه مقادیر موجود در متغیرها را چک کنید‪ .‬ویژوال استودیو برنامه شما را خطایابی میکند و حتی‬
‫خطاهای کوچک (مانند بزرگ یا کوچک نوشتن حروف) را برطرف میکند‪ ،‬همچنین دارای ابزارهای طراحی برای ساخت یک رابط گرافیکی است که بدون‬
‫ویژوال استودیو برای ساخت همچنین رابط گرافیکی باید کدهای زیادی نوشت‪ .‬با این برنامههای قدرتمند بازدهی شما افزایش مییابد و در وقت شما با وجود این‬
‫ویژگیهای شگفت انگیز صرفهجویی میشود‪.‬‬
‫در حال حاضر آخرین نسخه ویژوال استودیو ‪ Visual Studio 2019‬است‪ .‬این نسخه به دو نسخه ‪( Visual Studio Professional‬ارزان قیمت) و‬
‫‪( Visual Studio Enterprise‬گرانقیمت) تقسیم میشود و دارای ویژگیهای متفاوتی هستند‪ .‬خبر خوب برای توسعهدهندگان نرمافزار این است که‬
‫مایکروسافت تصمیم دارد که ویژوال استودیو را به صورت متن باز ارائه دهد‪ .‬یکی از نسخههای ویژوال استودیو‪ Visual Studio Community ،‬میباشد‬
‫که آزاد است و میتوان آن را دانلود و از آن استفاده کرد‪ .‬این برنامه ویژگیهای کافی را برای شروع برنامهنویسی ‪ C#‬در اختیار شما قرار میدهد‪ .‬این نسخه‬
‫(‪ )Community‬کامل نیست و خالصهشده نسخه اصلی است‪ .‬به هر حال استفاده از ‪ Visual Studio Community‬که جایگزین ‪Visual Studio‬‬
‫‪ Express‬شده و به نوعی همان نسخه ‪ Visual Studio Professional‬است‪ ،‬برای انجام تمرینات این سایت کافی است‪.‬‬
‫‪ Visual Studio Enterprise 2019‬دارای محیطی کاملتر و ابزارهای بیشتری جهت عیبیابی و رسم نمودارهای مختلف است که در ‪Visual‬‬
‫‪ Studio Community‬وجود ندارند‪ .‬ویژوال استودیو فقط به سی شارپ خالصه نمیشود و دارای زبانهای برنامهنویسی دیگری ازجمله ویژوال بیسیک نیز‬
‫می باشد‪ .‬رابط کاربری سی شارپ و ویژوال استودیو بسیار شبیه هم است و ما در این کتاب بیشتر تمرینات را با استفاده از سی شارپ انجام میدهیم‪.‬‬

‫دانلود و نصب ویژوال استودیو‬

‫در این درس میخواهیم نحوه دانلود و نصب نرم افزار ‪ Visual Studio Community 2019‬را آموزش دهیم‪ .‬در جدول زیر لیست نرم افزارها و سخت افزارهای الزم‬
‫جهت نصب ویژوال استودیو ‪ 2019‬آمده است‪:‬‬
‫سخت افزار‬ ‫سیستم عامل‬

‫‪1.6 GHz or faster processor‬‬ ‫‪Windows 10‬‬

‫)‪1 GB of RAM (1.5 GB if running on a virtual machine‬‬ ‫‪Windows 8.1‬‬

‫‪4 GB of available hard disk space‬‬ ‫‪Windows 8‬‬

‫‪5400 RPM hard disk drive‬‬ ‫‪Windows 7 Service Pack 1‬‬

‫‪DirectX 9-capable video card that runs at 1024 x 768 or higher display resolution‬‬ ‫‪Windows Server 2012 R2‬‬

‫‪Windows Server 2012‬‬

‫‪Windows Server 2008 R2 SP1‬‬

‫مراحل نصب ‪ Visual Studio Community 2019‬آغاز میشود (‪ Visual Studio Community 2019‬حدود ‪ 5‬گیگابایت حجم دارد و برای دانلود آن به‬
‫یک اینترنت پر سرعت دارید)‪:‬‬

‫‪10‬‬
‫بعد از گذراندن مرحله باال صفحه ای به صورت زیر باز میشود و از شما می خواهد که لحظاتی را منتظر بمانید‪:‬‬

‫سپس صفحه ای به صورت زیر به شما نمایش داده می شود‪ ،‬که شما باید در این صفحه گزینه های ‪ .Net Desktop Development‬و ‪Data Storage and‬‬
‫‪ Proccessing‬را تیک بزنید‪:‬‬

‫بعد از فشار دادن دکمه ‪ Modify‬در صفحه باال‪ ،‬شما وارد مراحل نصب ویژوال استودیو می شوید‪:‬‬

‫بعد از اتمام مراحل نصب‪ ،‬پیغامی مبنی بر ‪ Restart‬کردن سیستم به شما نمایش داده می شود‪:‬‬

‫بعد از این مرحله ویژوال استودیو به صورت کامل نصب شده و شما میتوانید از آن استفاده کنید‪.‬‬

‫شروع کار با ‪Visual Studio Community‬‬


‫برنامه ویژوال استودیو را اجرا کرده و منتظر بمانید تا صفحه آن بارگذاری شود‪:‬‬

‫اگر دارای یک اکانت مایکروسافت باشید میتوانید تغییراتی که در ویژوال استودیو میدهید را در فضای ابری ذخیره کرده و اگر آن را در کامپیوتر دیگر نصب کنید‪ ،‬میتوانید با‬
‫وارد شده به اکانت خود‪ ،‬تغییرات را به صورت خودکار بر روی ویژوال استودیویی که تازه نصب شده اعمال کنید‪ .‬البته میتوانید این مرحله را با زدن دکمه ‪Not now,‬‬
‫‪ maybe later‬رد کنید‪:‬‬

‫شما میتوانید از بین سه ظاهر از پیش تعریف شده در ویژوال استودیو یکی را انتخاب کنید‪ .‬من به صورت پیشفرض ظاهر ‪ Blue‬را انتخاب میکنم ولی شما میتوانید بسته به‬
‫سلیقه خود‪ ،‬ظاهر دیگر را انتخاب کنید‪:‬‬
‫بعد از زدن دکمه ‪ Start Visual Studio‬صفحه ای به صورت زیر ظاهر میشود‪:‬‬

‫بعد از بارگذاری کامل ‪ Visual Studio Community‬صفحه اصلی برنامه به صورت زیر نمایش داده میشود که نشان از نصب کامل آن دارد‪:‬‬

‫قانونی کردن ویژوال استودیو‬

‫‪ Visual Studio Community 2019‬رایگان است‪ .‬ولی گاهی اوقات ممکن است با پیغامی به صورت زیر مبنی بر منقضی شدن آن مواجه شوید‪:‬‬

‫‪11‬‬
‫همانطور که در شکل باال مشاهده میکنید‪ ،‬بر روی دکمه ‪ Signin‬کلیک میکنید تا وارد اکانت مایکروسافت خود شوید‪ .‬اگر اکانت ندارید‪ ،‬میتوانید از لینک زیر‬
‫یک اکانت ایجاد کنید‪:‬‬
‫‪create an account‬‬
‫بعد از ایجاد اکانت همانطور که در شکل باال مشاهده میکنید‪ ،‬بر روی گزینه ‪ Singin‬کلیک میکنیم‪ .‬با کلیک بر روی این گزینه صفحه ای به صورت زیر‬
‫ظاهر میشود که از شما مشخصات اکانتتان را میخواهد‪ ،‬آنها را وارد کرده و بر روی گزینه ‪ Singin‬کلیک کنید‪:‬‬

‫با کلیک بر روی گزینه ‪ Signin‬پنجره ای به صورت زیر نمایش داده میشود‪ ،‬منتظر میمانید تا پنجره بسته شود‪:‬‬

‫با بسته شدن پنجره باال‪ ،‬پنجره ای به صورت زیر ظاهر میشود که مشخصات اکانت شما در آن نمایش داده میشود‪ ،‬که نشان از ورود موفقیت آمیز شما دارد‪ .‬در‬
‫این صفحه بر روی گزینه ‪ Check an updated license‬کلیک کنید‪:‬‬

‫‪12‬‬
‫با کلیک بر روی این گزینه بعد از چند ثانیه پیغام ‪ we have updated your license successfully‬نمایش داده میشود و به این صورت ویژوال‬
‫استودیو قانونی میشود‪:‬‬

‫گردشی در ویژوال استودیو‬


‫‪ Visual Studio Community‬از تعداد زیادی پنجره و منو تشکیل شده است‪ ،‬که هر کدام برای انجام کار خاصی‪ ،‬به کار میروند‪ .‬اجازه دهید با نفوذ‬
‫بیشتر در محیط ویژوال سی شارپ با این قسمتها آشنا شویم‪ .‬از مسیر ‪ File > New Project‬یک برنامه جدید ایجاد کنید‪:‬‬

‫پنجره ای به شکل زیر نمایش داده خواهد شد‪:‬‬

‫‪13‬‬
‫در پنجره باال گزینه ‪ Windows From App‬را انتخاب کرده و بر روی گزینه ‪ Next‬کیلک کنید تا صفحه ای به صورت زیر ظاهر شود‪:‬‬

‫در شکل باال همه چیز را در حالت پیشفرض رها کرده و بر روی دکمه ‪ OK‬کلیک میکنیم تا صفحه زیر نمایان شود‪:‬‬

‫مشخصات فرم باال عبارت است از‪:‬‬

‫‪ -1‬صفحه طراحی (‪)Design‬‬

‫این صفحه در حکم یک ناحیه برای طراحی فرمهای ویندوزی شما است‪ .‬فرمهای ویندوزی رابطهای گرافیکی بین کاربر و کامپیوتر هستند و محیط ویندوز نمونه‬
‫بارزی از یک رابط گرافیکی یا ‪ GUI‬است‪ .‬شما در این صفحه میتوانید کنترلهایی مانند دکمهها‪ ،‬برچسبها و … به فرمتان اضافه کنید‪ .‬جزییات بیشتر در مورد‬
‫فرمهای ویندوزی و کنترلها و برنامه نویسی شیء گرا در فصل فرمهای ویندوزی آمده است‪ .‬اما توصیه میشود ابتدا مبانی برنامه نویسی را مطالعه کنید‪.‬‬

‫‪ -2‬مرورگر پروژه (‪)Solution Explorer‬‬

‫‪14‬‬
‫پروژه و فایلهای مربوط به آن را نشان میدهد‪ .‬یک ‪ Solution‬برنامه ای که توسط شما ساخته شده است را نشان میدهد‪ .‬ممکن است این برنامه یک پروژه‬
‫ساده یا یک پروژه چند بخشی باشد‪ .‬اگر ‪ Solution Explorer‬در صفحه شما نمایش داده نمیشود میتوانید از مسیر > ‪View > Other Windows‬‬
‫‪ Solution Explorer‬و یا با کلیدهای میانبر ‪ Ctrl+Alt+L‬آنرا نمایان کنید‪ .‬اگر چندین پروژه در حال اجرا هستند پروژه ای که با خط برجسته (‪)Bold‬‬
‫نشان داده شده پروژه فعال میباشد و هنگام اجرای برنامه اجرا میشود‪ .‬اگر بخواهید پروژه ای را که فعال نیست اجرا کنید‪ ،‬بر روی ‪Solution‬‬
‫‪Explorer‬کلیک راست کنید و سپس گزینه ‪ Set as StartUp Project‬را انتخاب نمایید‪ Solution Explorer.‬زیر یک ‪ Solution‬با ‪ 2‬پروژه را‬
‫نشان میدهد‪ .‬هر پروژه شامل فایلها و فولدرهای مربوط به خود است‪.‬‬

‫‪ -3‬پنجره خواص (‪)Properties‬‬

‫پنجره خواص (‪ )Properties‬خواص و رویدادهای مختلف هر آیتم انتخاب شده اعم از فرم‪ ،‬فایل‪ ،‬پروژه و کنترل را نشان میدهد‪ .‬اگر این پنجره مخفی است‬
‫میتوانید از مسیر ‪ View > Properties Window‬یا کلید میانبر ‪ F4‬آنرا ظاهر کنید‪ .‬در مورد خواص در درسهای آینده مفصل توضیح خواهیم داد‪.‬‬
‫خاصیتها‪ ،‬ویژگیها و صفات اشیا را نشان میدهند‪ .‬به عنوان مثال یک ماشین دارای خواصی مانند رنگ‪ ،‬سرعت‪ ،‬اندازه و مدل است‪.‬‬
‫اگر یک فرم یا کنترل را در صفحه طراحی و یا یک پروژه یا فایل را در ‪ SolutionExplorer‬انتخاب کنید پنجره خواص مربوط به آنها نمایش داده خواهد‬
‫شد‪ .‬این پنجره همچنین دارای رویدادهای مربوط به فرم یا کنترل انتخاب شده میباشد‪ .‬یک رویداد (‪ )event‬اتفاقی است که در شرایط خاصی پیش میآید‬
‫مانند وقتی که بر روی دکمه (‪ )button‬کلیک و یا متنی را در داخل جعبه متن (‪ )text box‬اصالح میکنیم‪.‬‬
‫کمبو باکس (‪ )combo box‬شکل باال که با حرف ‪ A‬نشان داده شده است به شما اجازه میدهد که شی مورد نظرتان (دکمه‪ ،‬فرم و…) را که میخواهید‬
‫خواص آنرا تغییر دهید انتخاب کنید‪ .‬این کار زمانی مفید است که کنترلهای روی فرم بسیار کوچک یا به هم نزدیک بوده و انتخاب آنها سخت باشد‪.‬‬
‫در زیر کمبو باکس باال دکمههای مفیدی قرار دارند (‪ .)B‬برخی از این دکمهها در شرایط خاصی فعال میشوند‪ .‬دکمه اول خاصیت اشیا را بر اساس دستههای‬
‫مختلفی مرتب میکند‪ .‬دومین دکمه خواص را بر اساس حروف الفبا مرتب میکند که پیشنهاد میکنیم از این دکمه برای دسترسی سریع به خاصیت مورد نظرتان‬

‫‪15‬‬
‫استفاده کنید‪ .‬سومین دکمه هم وقتی ظاهر می شود که یک کنترل یا یک فرم را در محیط طراحی انتخاب کنیم‪ .‬این دکمه به شما اجازه دسترسی به خواص فرم‬
‫ویا کنترل انتخاب شده را میدهد‪ .‬چهارمین دکم ه (که به شکل یک رعد و برق نمایش داده شده) رویدادهای فرم ویا کنترل انتخاب شده را میدهد‪.‬‬
‫در پایین شکل باال توضیحات کوتاهی در مورد خاصیتها و رویدادها نشان داده میشود‪ .‬بخش اصلی پنجره خواص (‪ )C‬شامل خواص و رویدادها است‪ .‬در ستون‬
‫سمت چپ نام رویداد یا خاصیت و در ستون سمت راست مقدار آنها آمده است‪ .‬در پایین پنجره خواص جعبه توضیحات (‪ )D‬قرار دارد که توضیحاتی درباره‬
‫خواص و رویدادها در آن نمایش داده میشود‪.‬‬

‫تغییر ظاهر ویژوال استودیو‬


‫اگر موقعیت پنجرهها و یا ظاهر برنامه ویژوال سی شارپ را دوست نداشته باشید‪ ،‬میتوانید به دلخواه آن را تغییر دهید‪ .‬برای این کار بر روی نوار عنوان ( ‪title‬‬
‫‪ )bar‬کلیک کرده و آنرا میکشید تا پنجره به شکل زیر به حالت شناور در آید‪:‬‬

‫در حالی که هنوز بر روی پنجره کلیک کردهاید و آن را میکشید یک راهنما (فلشی با چهار جهت) ظاهر میشود و شما را در قرار دادن پنجره در محل دلخواه‬
‫کمک میکند‪ .‬به عنوان مثال شما میتوانید پنجره را در باالترین قسمت محیط برنامه قرار دهید‪ .‬منطقه ای که پنجره قرار است در آنجا قرار بگیرد به رنگ آبی‬
‫در میآید‪:‬‬

‫‪16‬‬
‫منطقه ای که پنجره قرار است در آنجا قرار بگیرد به رنگ آبی در میآید‪.‬‬

‫پنجره در قسمت باالی محیط قرار داده شده است‪ .‬راهنمای صلیب شکل حاوی جعبههای مختلفی است که به شما اجازه میدهد پنجره انتخاب شده را در محل‬
‫دلخواه محیط ویژوال سی شارپ قرار دهید‪ .‬به عنوان مثال پنجره ‪ Properties‬را انتخاب کنید و آنرا به چپترین قسمت صلیب در پنجره نمایش داده شده‬
‫نزدیک و رها کنید‪:‬‬

‫مشاهده میکنید که پنجره مذکور در سمت چپ پنجره ‪ Design View‬قرار میگیرد‪:‬‬

‫‪17‬‬
‫کشیدن پنجره به مرکز صلیب راهنما باعث ترکیب آن با پنجره مقصد میشود که در مثال باال شما می توانید به عنوان یک تب به پنجره ‪ Properties‬دست‬
‫پیدا کنید‪.‬‬

‫اگر به عنوان مثال پنجره ‪ Properties‬را روی پنجره ‪ Solution Explorer‬بکشید‪ ،‬یک صلیب راهنمای دیگر نشان داده میشود‪ .‬با کشیدن پنجره به‬
‫قسمت پایینی صلیب پنجره ‪ Properties‬زیر پنجره ‪ Solution Explorer‬قرار خواهد گرفت‪.‬‬

‫‪18‬‬
‫قسمتی از محیط برنامه که میخواهید پنجره در آنجا قرار بگیرد به رنگ آبی در میآید‪ .‬ویژوال سی شارپ همچنین دارای خصوصیتی به نام ‪ autohide‬است‬
‫که به صورت اتوماتیک پنجرهها را مخفی میکند‪ .‬هر پنجره دارای یک آیکون سنجاق مانند نزدیک دکمه ‪ close‬میباشد‪.‬‬

‫بر روی این آیکون کلیک کنید تا ویژگی ‪ auto-hide‬فعال شود‪ .‬برای دسترسی به هر یک از پنجرهها میتوان با ماوس بر روی آنها توقف یا بر روی تبهای‬
‫کنار محیط ویژوال سی شارپ کلیک کرد‪.‬‬

‫‪19‬‬
‫برای غیر فعال کردن این ویژگی در هر کدام از پنجرهها کافیست پنجره را انتخاب کرده و دوباره بر روی آیکون مورد نظر کلیک کنید‪.‬‬

‫به این نکته توجه کنید که اگر شکل آیکون افقی بود بدین معناست که ویژگی فعال و اگر شکل آن عمودی بود به معنای غیر فعال بود ویژگی ‪auto-hide‬‬
‫میباشد‪.‬‬

‫ساخت یک برنامه ساده‬

‫اجازه بدهید یک برنامه بسیار ساده به زبان سی شارپ بنویسیم‪ .‬این برنامه یک پیغام را در محیط کنسول نمایش میدهد‪ .‬در این درس میخواهم ساختار و دستور‬
‫زبان یک برنامه ساده سی شارپ را توضیح دهم‪ .‬برنامه ‪ Visual Studio Community‬را اجرا کنید‪ .‬از مسیر ‪ Create New Project‬یک پروژه‬
‫جدید ایجاد کنید‪:‬‬

‫سپس صفحه ای به صورت زیر به شما نمایش داده می شود که در آن شما می بایست گزینه ‪ Console App‬را انتخاب کرده و سپس بر روی گزینه ‪Next‬‬
‫کلیک کنید‪:‬‬

‫‪20‬‬
‫حال با یک صفحه مواجه میشوید که از شما میخواهد نام پروژهتان را انتخاب و آن را ایجاد کنید (شکل زیر)‪:‬‬

‫نام پروژهتان را ‪ MyFirstProgram‬بگذارید‪ .‬یک ‪ Console Application‬برنامه ای تحت داس در محیط ویندوز است و فاقد محیط گرافیکی‬
‫می باشد‪ .‬بهتر است برنامه خود را در محیط کنسول بنویسید تا بیشتر با مفهوم برنامه نویسی آشنا شوید‪ .‬بعد از اینکه آموزش مبانی زبان به پایان رسید‪ ،‬برنامه‬
‫نویسی در محیط ویندوز و بخش بصری سی شارپ را آموزش خواهیم داد‪ .‬بعد از فشردن دکمه ‪ ،Create‬برنامه ‪ Visual C#‬یک ‪ solution‬در یک فولدر‬
‫موقتی ایجاد میکند‪ .‬یک ‪ solution‬مجموعه ای از پروژههاست‪ ،‬اما در بیشتر تمرینات شامل یک پروژه میباشد‪ .‬فایل ‪ solution‬دارای پسوند ‪ .sln‬میباشد‬

‫‪21‬‬
‫و شامل جزییاتی در مورد پروژهها و فایلهای وابسته به آن میباشد‪ .‬پروژه جدید همچنین حاوی یک فایل با پسوند ‪ .csproj‬میباشد که آن نیز شامل جزییاتی‬
‫در مورد پروژهها و فایلهای وابسته به آن میباشد‪ .‬حال میخواهیم شما را با محیط کد نویسی آشنا کنیم‪.‬‬

‫محیط کدنویسی جایی است که ما کدها را در آن تایپ میکنیم‪ .‬کدها در محیط کدنویسی به صورت رنگی تایپ میشوند‪ ،‬در نتیجه تشخیص بخشهای مختلف‬
‫کد را راحت میکند‪ .‬منوی سمت چپ (شماره ‪ )1‬شامل نام پروژه ای که ایجاد کردهاید‪ ،‬منوی وسط (شماره ‪ )2‬شامل لیست کالسها‪ ،‬ساختارها‪ ،‬انواع شمارشی و‬
‫منوی سمت راست (شماره ‪ )3‬شامل اعضای کالسها‪ ،‬ساختارها‪ ،‬انواع شمارشی و… میباشد‪ .‬نگران اصطالحاتی که به کار بردیم نباشید آنها را در فصول بعد‬
‫توضیح خواهم داد‪ .‬همه فایلهای دارای کد در سی شارپ دارای پسوند ‪ .cs‬هستند‪ .‬در محل کد نویسی کدهایی از قبل نوشته شده که برای شروع شما آنها را‬
‫پاک کنید و کدهای زیر را در محل کدنویسی بنویسید‪:‬‬

‫‪1: namespace MyFirstProgram‬‬


‫{ ‪2:‬‬
‫‪3:‬‬ ‫‪class Program‬‬
‫‪4:‬‬ ‫{‬
‫‪5:‬‬ ‫)(‪static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;)"!‪System.Console.WriteLine("Welcome to Visual C# Tutorials‬‬
‫‪8:‬‬ ‫}‬
‫‪9:‬‬ ‫}‬
‫} ‪10:‬‬

‫ساختار یک برنامه در سی شارپ‬

‫مثال باال سادهترین برنامه ای است که شما میتوانید در سی شارپ بنویسید‪ .‬هدف در مثال باال نمایش یک پیغام در صفحه نمایش است‪ .‬هر زبان برنامه نویسی‬
‫دارای قواعدی برای کدنویسی است‪ .‬اجازه بدهید هر خط کد را در مثال باال توضیح بدهیم‪ .‬در خط اول فضای نام (‪ )namespace‬تعریف شده است که شامل‬
‫کدهای نوشته شده توسط شما است و از تداخل نامها جلوگیری میکند‪ .‬درباره فضای نام در درسهای آینده توضیح خواهیم داد‪.‬‬

‫‪22‬‬
‫در خط دوم آکوالد (}) نوشته شده است‪ .‬آکوالد برای تعریف یک بلوک کد به کار میرود‪ .‬سی شارپ یک زبان ساخت یافته است که شامل کدهای زیاد و‬
‫ساختارهای فراوانی میباشد‪ .‬هر آکوالد باز (}) در سی شارپ باید دارای یک آکوالد بسته ({) نیز باشد‪ .‬همه کدهای نوشته شده از خط ‪ 2‬تا خط ‪ 10‬یک بلوک‬
‫کد یا بدنه فضای نام است‪.‬‬
‫در خط ‪ 3‬یک کالس تعریف شده است‪ .‬درباره کالسها در فصلهای آینده توضیح خواهیم داد‪ .‬در مثال باال کدهای شما باید در داخل یک کالس نوشته شود‪.‬‬
‫بدنه کالس شامل کدهای نوشته شده از خط ‪ 4‬تا ‪ 9‬میباشد‪ .‬خط ‪ 5‬متد )(‪ Main‬یا متد اصلی نامیده میشود‪ .‬هر متد شامل یک سری کد است که وقتی اجرا‬
‫می شوند که متد را صدا بزنیم‪ .‬درباره متد و نحوه صدا زدن آن در فصول بعدی توضیح خواهیم داد‪ .‬متد ‪ Main‬نقطه آغاز اجرای برنامه است‪ .‬این بدان معناست‬
‫که ابتدا تمام کدهای داخل متد )(‪ Main‬و سپس بقیه کدها اجرا میشود‪ .‬درباره متد )(‪ Main‬در فصول بعدی توضیح خواهیم داد‪ .‬متد )(‪ Main‬و سایر‬
‫متدها دارای آکوالد و کدهایی در داخل آنها میباشند و وقتی کدها اجرا میشوند که متدها را صدا بزنیم‪ .‬هر خط کد در سی شارپ به یک سمیکالن (;) ختم‬
‫میشود‪ .‬اگر سمیکالن در آخر خط فراموش شود برنامه با خطا مواجه میشود‪ .‬مثالی از یک خط کد در سی شارپ به صورت زیر است‪:‬‬

‫;)"!‪System.Console.WriteLine("Welcome to Visual C# Tutorials‬‬

‫این خط کد پیغام !‪ Welcome to Visual C# Tutorials‬را در صفحه نمایش نشان میدهد‪ .‬از متد )(‪ WriteLine‬برای چاپ یک رشته استفاده‬
‫میشود‪ .‬یک رشته گروهی از کاراکترها است‪ ،‬که به وسیله دابل کوتیشن (“) محصور شده است‪ .‬مانند‪.“Welcome to Visual C# Tutorials!”:‬‬
‫یک کاراکتر میتواند یک حرف‪ ،‬عدد‪ ،‬عالمت یا … باشد‪ .‬در کل مثال باال نحوه استفاده از متد )(‪ WriteLine‬است که در داخل کالس ‪ Console‬که آن نیز‬
‫به نوبه خود در داخل فضای نام ‪ MyFirstProgram‬قرار دارد را نشان میدهد‪ .‬توضیحات بیشتر در درسهای آینده آمده است‪ .‬سی شارپ فضای خالی و‬
‫خطوط جدید را نادیده میگیرد‪ .‬بنابراین شما میتوانید همه برنامه را در یک خط بنویسید‪ .‬اما اینکار خواندن و اشکال زدایی برنامه را مشکل میکند‪ .‬یکی از‬
‫خطاهای معمول در برنامه نویسی فراموش کردن سمیکالن در پایان هر خط کد است‪ .‬به مثال زیر توجه کنید‪:‬‬

‫(‪System.Console.WriteLine‬‬
‫;)"!‪"Welcome to Visual C# Tutorials‬‬

‫سی شارپ فضای خالی باال را نادیده میگیرد و از کد باال اشکال نمیگیرد‪ .‬اما از کد زیر ایراد میگیرد‪.‬‬

‫;(‪System.Console.WriteLine‬‬
‫;)"!‪"Welcome to Visual C# Tutorials‬‬

‫به سمیکالن آخر خط اول توجه کنید‪ .‬برنامه با خطای نحوی مواجه میشود چون دو خط کد مربوط به یک برنامه هستند و شما فقط باید یک سمیکالن در آخر آن‬
‫قرار دهید‪ .‬همیشه به یاد داشته باشید که سی شارپ به بزرگی و کوچکی حروف حساس است‪ .‬یعنی به طور مثال ‪ MAN‬و ‪ man‬در سی شارپ با هم فرق‬
‫دارند‪ .‬رشتهها و توضیحات از این قاعده مستثنی هستند که در درسهای آینده توضیح خواهیم داد‪ .‬مثالً کدهای زیر با خطا مواجه میشوند و اجرا نمیشوند‪:‬‬

‫;)"!‪system.console.writeline("Welcome to Visual C# Tutorials‬‬


‫;)"!‪SYSTEM.CONSOLE.WRITELINE("Welcome to Visual C# Tutorials‬‬
‫;)"!‪sYsTem.cONsoLe.wRItelIne("Welcome to Visual C# Tutorials‬‬

‫تغییر در بزرگی و کوچکی حروف از اجرای کدها جلوگیری میکند‪ .‬اما کد زیر کامالً بدون خطا است‪:‬‬

‫;)"!‪System.Console.WriteLine("WELCOME TO VISUAL C# TUTORIALS‬‬

‫همیشه کدهای خود را در داخل آکوالد بنویسید‪.‬‬

‫{‬
‫;‪statement1‬‬
‫}‬

‫‪23‬‬
‫این کار باعث میشود که کدنویسی شما بهتر به چشم بیاید و تشخیص خطاها راحت تر باشد‪ .‬یکی از ویژگیهای مهم سی شارپ نشان دادن کدها به صورت تو‬
‫رفتگی است بدین معنی که کدها را به صورت تو رفتگی از هم تفکیک میکند و این در خوانایی برنامه بسیار مؤثر است‪.‬‬

‫ذخیره پروژه و برنامه‬

‫برای ذخیره پروژه و برنامه میتوانید به مسیر ‪ File > Save All‬بروید یا از کلیدهای میانبر ‪ Ctrl+Shift+S‬استفاده کنید‪ .‬همچنین میتوانید از قسمت‬

‫کلیک کنید‪ .‬برای ذخیره یک فایل ساده میتوانید به مسیر )‪ File > Save (FileName‬بروید یا از کلیدهای میانبر‬ ‫‪ Toolbar‬بر روی شکل‬

‫کلیک کنید‪ .‬برای باز کردن یک پروژه یا برنامه از منوی ‪ File‬گزینه‬ ‫‪ Ctrl+S‬استفاده کنید‪ .‬همچنین میتوانید از قسمت ‪ Toolbar‬بر روی شکل‬

‫در ‪ toolbar‬کلیک کنید‪ .‬سپس به محلی که پروژه در آنجا ذخیره شده میروید و فایلی با پسوند ‪ sln‬یا پروژه‬ ‫‪ Open‬را انتخاب میکنید یا بر روی آیکون‬
‫با پسوند ‪ .csproj‬را باز میکنید‪.‬‬

‫کامپایل برنامه‬

‫همانطور که قبالً ذکر شد‪ ،‬کدهای سی شارپ قبل از اجرا‪ ،‬ابتدا به زبان میانی ترجمه میشوند‪ .‬برای کامپایل برنامه از منوی ‪ Debug‬گزینه ‪Build‬‬
‫‪ Solution‬را انتخاب میکنید یا دکمه ‪ F6‬را بر روی صفحه کلید فشار میدهیم‪ .‬این کار همه پروژههای داخل ‪ solution‬را کامپایل میکند‪ .‬برای کامپایل‬
‫یک قسمت از ‪ solution‬به ‪ Solution Explorer‬میرویم و بر روی آن قسمت راست کلیک کرده و از منوی باز شوند گزینه ‪ build‬را انتخاب میکنید‪.‬‬
‫مانند شکل زیر‪:‬‬

‫اجرای برنامه‬

‫وقتی ما برنامه مان را اجرا میکنیم سی شارپ به صورت اتوماتیک کدهای ما را به زبان میانی مایکروسافت کامپایل میکند‪ .‬دو راه برای اجرای برنامه وجود دارد‪:‬‬

‫‪ .1‬اجرا همراه با اشکال زدایی (‪)Debug‬‬


‫‪ .2‬اجرا بدون اشکال زدایی (‪)Non-Debug‬‬

‫‪24‬‬
‫اجرای بدون اشکال زدایی برنامه‪ ،‬خطاهای برنامه را نادیده میگیرد‪ .‬با اجرای برنامه در حالت ‪ Non-Debug‬سریعاً برنامه اجرا میشود و شما با زدن یک دکمه‬
‫از برنامه خارج میشوید‪ .‬در حالت پیش فرض حالت ‪ Non-Debug‬مخفی است و برای استفاده از آن میتوان از منوی ‪ Debug‬گزینه ‪Start Without‬‬
‫‪ Debuging‬را انتخاب کرد یا از دکمههای ترکیبی ‪ Crl + F5‬استفاده نمود‪:‬‬
‫!‪Welcome to Visual C# Tutorials‬‬
‫‪Press any key to continue...‬‬

‫به این نکته توجه کنید که پیغام …‪ Press any key to continue‬جز خروجی به حساب نمیآید و فقط نشان دهنده آن است که برنامه در حالت ‪Non-‬‬
‫‪ Debug‬اجرا شده است و شما میتوانید با زدن یک کلید از برنامه خارج شوید‪ .‬دسترسی به حالت ‪ Debug Mode‬آسان تر است و به صورت پیشفرض‬
‫برنامهها در این حالت اجرا میشوند‪ .‬از این حالت برای رفع خطاها و اشکال زدایی برنامهها استفاده میشود که در درسهای آینده توضیح خواهیم داد‪ .‬شما‬
‫همچنین میتوانید از ‪ break points‬و قسمت ‪ Help‬برنامه در مواقعی که با خطا مواجه میشوید استفاده کنید‪ .‬برای اجرای برنامه با حالت ‪Debug‬‬
‫‪ Mode‬میتوانید از منوی ‪ Debug‬گزینه ‪ Start Debugging‬را انتخاب کرده و یا دکمه ‪ F5‬را فشار دهید‪ .‬همچنین میتوانید بر روی شکل‬

‫در ‪ toolbar‬کلیلک کنید‪ .‬اگر از حالت ‪ Debug Mode‬استفاده کنید برنامه نمایش داده شده و فوراً ناپدید میشود‪ .‬برای جلوگیری از این اتفاق‬
‫شما میتوانید از کالس و متد )(‪ System.Console.ReadKey‬برای توقف برنامه و گرفتن ورودی از کاربر جهت خروج از برنامه استفاده کنید‪( .‬درباره‬
‫متدها در درسهای آینده توضیح خواهیم داد‪).‬‬

‫‪namespace MyFirstProgram‬‬
‫{‬
‫‪class Program‬‬
‫{‬
‫)(‪static void Main‬‬
‫{‬
‫;)"!‪System.Console.WriteLine("Welcome to Visual C# Tutorials‬‬
‫;)(‪System.Console.ReadKey‬‬
‫}‬
‫}‬
‫}‬

‫حال برنامه را در حالت ‪ Debug Mode‬اجرا میکنیم‪ .‬مشاهده میکنید که برنامه متوقف شده و از شما در خواست ورودی میکند‪ ،‬به سادگی و با زدن دکمه‬
‫‪Enter‬از برنامه خارج شوید‪ .‬من از حالت ‪ Non-Debug‬به این علت استفاده کردم تا نیازی به نوشتن کد اضافی )(‪ Console.ReadKey‬نباشد‪ .‬از این‬
‫به بعد هر جا ذکر شد که برنامه را اجرا کنید برنامه را در حالت ‪ Non-Debug‬اجرا کنید‪ .‬وقتی به مبحث استثناءها رسیدیم از حالت ‪ Debug‬استفاده میکنیم‪.‬‬

‫وارد کردن فضای نام در برنامه‬

‫فضای نام (‪ )Namespace‬در برگیرنده کدهایی است که شما در برنامهتان از آنها استفاده میکنید‪ .‬در برنامه فوق ما یک فضای نام در برنامه مان با نام‬
‫‪ MyFirstProgram‬داریم‪ ،‬اما دات نت دارای هزاران فضای نام میباشد‪ .‬یکی از این فضاهای نامی‪ ،‬فضای نام ‪ System‬است که شامل کدهایی است که‬
‫در یک برنامه ابتدایی ‪ C#‬به کار میروند‪ .‬کالس ‪ Console‬که ما از آن در برنامه باال استفاده کردیم در این فضای نام قرار دارد‪.‬‬

‫;)"!‪System.Console.WriteLine("Welcome to Visual C# Tutorials‬‬


‫;)(‪System.Console.ReadKey‬‬

‫اینکه قبل از استفاده از هر کالس ابتدا فضای نام آن را مانند کد باال بنویسیم کمی خسته کننده است‪ .‬خوشبختانه دات نت به ما اجازه میدهد که برای جلوگیری‬
‫از تکرار مکررات‪ ،‬فضاهای نامی را که قرار است در برنامه استفاده کنیم با استفاده از دستور ‪ using‬در ابتدای برنامه وارد نماییم‪:‬‬

‫‪25‬‬
‫;‪using namespace‬‬

‫دستور باال نحوه وارد کردن یک فضای نام در برنامه را نشان میدهد‪ .‬در نتیجه به جای آنکه به صورت زیر ابتدا نام فضای نام و سپس نام کالس را بنویسیم‪:‬‬

‫;)"!‪System.Console.WriteLine("Hello World‬‬

‫میتوانیم فضای نام را با دستوری که ذکر شد وارد برنامه کرده و کد باال را به صورت خالصه شده زیر بنویسیم‪:‬‬

‫;)"‪Console.WriteLine("Hello World‬‬

‫دستورات ‪ using‬که باعث وارد شدن فضاهای نامی به برنامه میشوند عموماً در ابتدای برنامه و قبل از همه کدها نوشته میشوند‪ ،‬پس برنامهی این درس را‬
‫میتوان به صورت زیر نوشت‪:‬‬

‫;‪using System‬‬

‫‪namespace MyFirstProgram‬‬
‫{‬
‫‪class Program‬‬
‫{‬
‫)(‪static void Main‬‬
‫{‬
‫;)"!‪Console.WriteLine("Welcome to Visual C# Tutorials‬‬
‫;)(‪Console.ReadKey‬‬
‫}‬
‫}‬
‫}‬

‫هنگامی که یک برنامه در ویژوال استودیو ایجاد میکنید‪ ،‬اگر وجود برخی از فضاهای نام الزامی نباشد‪ ،‬ویژوال استودیو ‪ 2017‬آنها را به صورت کم رنگ نمایش‬
‫میدهد‪ ،‬و شما میتوانید بدون هیچ مشکلی این فضاهای نام را پاک کنید‪:‬‬

‫‪26‬‬
‫در نسخههای قبلی ویژوال استودیو هم برای پاک کردن فضاهای نام غیر قابل استفاده‪ ،‬ابتدا بر روی یکی از آنها راست کلیک کرده و سپس بر روی‬
‫‪ Remove and Sort Usings‬کلیک کنید‪:‬‬

‫اگر از کالسی استفاده کنید که از قبل فضای نام مربوط به آن را وارد برنامه نکرده باشید در زیر آن کالس خط قرمز کشیده میشود‪:‬‬

‫برای رفع این مشکل‪ ،‬اگر از قبل نام فضای مربوطه را بلد باشید که باید آن را در قسمت فضای نام وارد کنید‪ .‬در غیر اینصورت‪ ،‬بر روی نام کالس با ماوس کمی‬
‫مکث کنید تا یک پنجره ‪ popup‬ظاهر شده و آن را به شما معرفی کند‪:‬‬

‫‪27‬‬
‫در این صورت با کلیک بر روی آن‪ ،‬ویژوال استودیو به طور خودکار فضای نام را وارد برنامه میکند‪:‬‬

‫در مورد فضای نام در درسهای آینده بیشتر توضیح میدهیم‪ .‬همانطور که قبال هم ذکر شد‪ ،‬با ورود نسخه های جدید سی شارپ‪ ،‬قابلیت های جدیدی به این‬
‫زبان اضافه می شود که کدنویسی را راحت تر می کنند‪ .‬مثال کد این درس را در نسخه های جدید می توان به صورت زیر نوشت‪:‬‬

‫;‪1: using static System.Console‬‬


‫‪2:‬‬

‫‪28‬‬
‫‪3: namespace MyFirstProgram‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫‪class Program‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫)‪static void Main(string[] args‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫;)"!‪WriteLine("Welcome to Visual C# Tutorials‬‬
‫‪10:‬‬ ‫;)(‪ReadKey‬‬
‫‪11:‬‬ ‫}‬
‫‪12:‬‬ ‫}‬
‫} ‪13:‬‬

‫به این حد توضیح در مورد کد باال بسنده می کنیم که شما در نسخه های جدید کافیست یکبار عبارت ‪ System.Console‬را در قسمت فضاهای نام بنویسید‬
‫تا هر بار الزم نباشد که آن را در خطوط ‪ 9‬و ‪ 10‬ذکر کنید‪ .‬در مورد تمامی کلمات گفته شده در این درس که برای شما نامفهوم هستند در درس های آینده‬
‫توضیح می دهیم‪ .‬حال که با خصوصیات و ساختار اولیه سی شارپ آشنا شدید در درسهای آینده مطالب بیشتری از این زبان برنامه نویسی قدرتمند خواهید‬
‫آموخت‪.‬‬

‫استفاده از ‪IntelliSense‬‬
‫شاید یکی از ویژگیهای مهم ‪ ،Visual Studio‬اینتلی سنس باشد‪ IntelliSense .‬ما را قادر میسازد که به سرعت به کالسها و متدها و … دسترسی پیدا‬
‫کنیم‪ .‬وقتی که شما در محیط کدنویسی حرفی را تایپ کنید‪ IntelliSense ،‬فوراً فعال میشود‪ .‬کد زیرا را در داخل متد )(‪ Main‬بنویسید‪.‬‬

‫;)"!‪System.Console.WriteLine("Welcome to Visual C# Tutorials‬‬

‫اولین حرف را تایپ کنید تا ‪ IntelliSense‬فعال شود‪.‬‬

‫‪ IntelliSense‬لیستی از کلمات به شما پیشنهاد میدهد که بیشترین تشابه را با نوشته شما دارند‪ .‬شما میتوانید با زدن دکمه ‪ tab‬گزینه مورد نظرتان را‬
‫انتخاب کنید‪ .‬با تایپ نقطه ( ‪ ) .‬شما با لیست پیشنهادی دیگری مواجه میشوید‪.‬‬

‫‪29‬‬
‫اگر بر روی گزینه ای که می خواهید انتخاب کنید لحظه ای مکث کنید‪ ،‬توضیحی در رابطه با آن مشاهده خواهید کرد مانند شکل باال‪ .‬هر چه که به پایان کد‬
‫نزدیک میشوید لیست پیشنهادی محدود تر میشود‪ .‬برای مثال با تایپ حرف ‪ W،IntelliSense‬فقط کلماتی را که دارای حرف ‪ W‬هستند را نمایش‬
‫میدهد‪.‬‬

‫با تایپ حرفهای بیشتر لیست محدودتر شده و فقط دو کلمه را نشان میدهد‪.‬‬

‫اگر ‪ IntelliSense‬نتواند چیزی را که شما تایپ کردهاید پیدا کند‪ ،‬هیچ چیزی را نمایش نمیدهد‪ .‬برای ظاهر کردن ‪ IntelliSense‬کافیست دکمه ترکیبی‬
‫‪ Ctrl+Space‬را فشار دهید‪ .‬برای انتخاب یکی از متدهایی که دارای چند حالت هستند‪ ،‬میتوان با استفاده از دکمههای مکان نما (باال و پایین) یکی از حالتها‬
‫را انتخاب کرد‪ .‬مثالً متد )(‪ Writeline‬همانطور که در شکل زیر مشاهده میکنید دارای ‪ 19‬حالت نمایش پیغام در صفحه است‪.‬‬

‫‪ IntelliSense‬به طور هوشمند کدهایی را به شما پیشنهاد میدهد و در نتیجه زمان نوشتن کد را کاهش میدهد‪ .‬در ویژوال استودیو هر جزء دارای یک آیکون‬
‫منحصر به فرد میباشد‪ .‬در زیر لیست آیکونهای ویژوال استودیو آمده است ‪:‬‬
‫آیکون مربوط به‬

‫پارامترها و متغیرهای محلی)‪(Locals and Parameters‬‬

‫ثابت)‪(Constant‬‬

‫خاصیت)‪(Property‬‬

‫‪30‬‬
‫آیکون مربوط به‬

‫رویداد)‪(Event‬‬

‫فیلد)‪(Field‬‬

‫متد)‪(Method‬‬

‫رابط)‪(Interface‬‬

‫کالس)‪(Class‬‬

‫ساختار)‪(Structure‬‬

‫نوع شمارشی)‪(Enum‬‬

‫نماینده)‪(Delegate‬‬

‫فضای نام)‪(Namespace‬‬

‫کلمه کلیدی)‪(Keyword‬‬

‫کد کوتاه)‪(Code Snippet‬‬

‫نگران اسامی ذکر شده در جدول باال نباشید‪ .‬آنها را در درسهای آینده توضیح خواهیم داد‪ .‬یکی از قابلیتهای جدید که در ویژوال استودیو ‪ 2017‬اضافه شده‬
‫است‪ ،‬مرتب کردن لیست ‪ IntelliSense‬میباشد‪ .‬فرض کنید که شما میخواهید همه کالسهایی دارای حرف ‪ S‬هستند را در لیست داشته باشید‪ .‬برای این‬
‫کار کافیست بر روی آیکون کالس در ‪ IntelliSense‬کلیک کنید ‪:‬‬

‫همانطور که در شکل باال مشاهده میکنید همه کالسهایی که دارای حرف ‪ S‬هستند‪ ،‬لیست می شوند‪ .‬در زیر یکی دیگر از امکانات ویژوال استودیو که باعث‬
‫راحتی در کدنویسی میشوند‪ Code Snippet ،‬ها هستند‪ Code Snippet .‬ها در واقعاً مخفف برخی کلمات یا عبارات در ویژوال استودیو هستند‪ .‬مثالً به‬
‫جای نوشتن عبارت ;)(‪ System.Console.WriteLine‬میتوانید ‪ cw‬را نوشته و سپس دو بار دکمه ‪ Tab‬را بزنید تا ویژوال استودیو عبارت مذکور را‬
‫برای شما کامل کند ‪:‬‬

‫‪31‬‬
‫رفع خطاها‬

‫بیشتر اوقات هنگام برنامه نویسی با خطا مواجه میشویم‪ .‬تقریباً همه برنامههایی که امروزه میبینید حداقل از داشتن یک خطا رنج میبرند‪ .‬خطاها میتوانند برنامه‬
‫شما را با مشکل مواجه کنند‪ .‬در سی شارپ سه نوع خطا وجود دارد ‪:‬‬

‫خطای کامپایلری‬
‫این نوع خطا از اجرای برنامه شما جلوگیری میکند‪ .‬این خطاها شامل خطای دستور زبان میباشد‪ .‬این بدین معنی است که شما قواعد کد نویسی را رعایت‬
‫نکردهاید‪ .‬یکی دیگر از موارد وقوع این خطا هنگامی است که شما از چیزی استفاده میکنید که نه وجود دارد و نه ساخته شده است‪ .‬حذف فایلها یا اطالعات‬
‫ناقص در مورد پروژه ممکن است باعث به وجود آمدن خطای کامپایلری شود‪ .‬استفاده از برنامه بوسیله برنامه دیگر نیز ممکن است باعث جلوگیری از اجرای‬
‫برنامه و ایجاد خطای کامپایلری شود‪.‬‬

‫خطاهای منطقی‬

‫این نوع خطا در اثر تغییر در یک منطق موجود در برنامه به وجود می آید‪ .‬رفع این نوع خطاها بسیار سخت است چون شما برای یافتن آنها باید کد را تست کنید‪.‬‬
‫نمونهای از یک خطای منطقی برنامهای است که دو عدد را جمع میکند ولی حاصل تفریق دو عدد را نشان میدهد‪ .‬در این حالت ممکن است‪ ،‬برنامه نویس‬
‫عالمت ریاضی را اشتباه تایپ کرده باشد‪.‬‬

‫استثناء‬

‫این نوع خطاها هنگامی رخ میدهند که برنامه در حال اجراست‪ .‬این خطا هنگامی روی میدهد که کاربر یک ورودی نامعتبر به برنامه بدهد و برنامه نتواند آن را‬
‫پردازش کند‪ .‬ویژوال استودیو و ویژوال سی شارپ دارای ابزارهایی برای پیدا کردن و برطرف کردن خطاها هستند‪ .‬وقتی در محیط کدنویسی در حال تایپ کد‬
‫هستیم یکی از ویژگیهای ویژوال استودیو تشخیص خطاهای ممکن قبل از اجرای برنامه است‪ .‬زیر کدهایی که دارای خطای کامپایلری هستند خط قرمز کشیده‬
‫میشود‪.‬‬

‫‪32‬‬
‫هنگامی که شما با ماوس روی این خطوط توقف کنید توضیحات خطا را مشاهده میکنید‪ .‬شما ممکن است با خط سبز هم مواجه شوید که نشان دهنده اخطار در‬
‫کد است ولی به شما اجازه اجرای برنامه را میدهند‪ .‬به عنوان مثال ممکن است شما یک متغیر را تعریف کنید ولی در طول برنامه از آن استفاده نکنید‪( .‬در‬
‫درسهای آینده توضیح خواهیم داد)‪.‬‬

‫درباره رفع خطاها در آینده توضیح بیشتری میدهیم‪( ErrorList .‬لیست خطاها) که در شکل زیر با فلش قرمز نشان داده شده است به شما امکان مشاهده‬
‫خطاها‪ ،‬هشدارها و رفع آنها را میدهد‪ .‬برای باز کردن ‪ Error List‬میتوانید به مسیر ‪ Error List > Other Windows > View‬بروید‪.‬‬

‫‪33‬‬
‫همانطور که در شکل زیر مشاهده میکنید هرگاه برنامه شما با خطا مواجه شود لیست خطاها در ‪ Error List‬نمایش داده میشود‪.‬‬

‫در شکل باال تعدادی خطا همراه با راه حل رفع آنها در ‪ Error List‬نمایش داده شده است‪ Error List .‬دارای چندین ستون است که به طور کامل جزییات‬
‫خطاها را نمایش میدهند‪.‬‬
‫توضیحات‬ ‫ستون‬

‫‪ Description‬توضیحی درباره خطا‬

‫فایلی که خطا در آن اتفاق افتاده است‬ ‫‪File‬‬

‫شماره خطی از فایل که دارای خطاست‬ ‫‪Line‬‬

‫ستون یا موقعیت افقی خطا در داخل خط‬ ‫‪Column‬‬

‫نام پروژهای که دارای خطاست ‪.‬‬ ‫‪Project‬‬

‫اگر برنامه شما دارای خطا باشد و آن را اجرا کنید با پنجره زیر روبرو میشوید ‪:‬‬

‫‪34‬‬
‫مربع کوچک داخل پنجره باال را تیک زنید چون دفعات بعد که برنامه شما با خطا مواجه شود دیگر این پنجره به عنوان هشدار نشان داده نخواهد شد‪ .‬با کلیک بر‬
‫روی دکمه ‪ Yes‬برنامه با وجود خطا نیز اجرا میشود‪ .‬اما با کلیک بر روی دکمه ‪ NO‬اجرای برنامه متوقف میشود و شما باید خطاهای موجود در پنجره‬
‫‪ Error List‬را بر طرف نمایید‪ .‬یکی دیگر از ویژگیهای مهم پنجره ‪ Error List‬نشان دادن قسمتی از برنامه است که دارای خطاست‪ .‬با یک کلیک ساده بر‬
‫روی هر کدام خطاهای موجود در پنجره ‪ ، Error List‬محل وقوع خطا نمایش داده میشود‪.‬‬

‫توضیحات‬

‫وقتی که کدی تایپ می کنید شاید بخواهید که متنی جهت یادآوری وظیفه آن کد به آن اضافه کنید‪ .‬در سی شارپ (و بیشتر زبانهای برنامه نویسی) می توان این‬
‫کار را با استفاده از توضیحات انجام د اد‪ .‬توضیحات متونی هستند که توسط کامپایلر نادیده گرفته می شوند و به عنوان بخشی از کد محسوب نمی شوند‪.‬‬
‫هدف اصلی از ایجاد توضیحات‪ ،‬باال بردن خوانایی و تشخیص نقش کدهای نوشته شده توسط شما ‪ ،‬برای دیگران است‪ .‬فرض کنید که می خواهید در مورد یک‬
‫کد خاص‪ ،‬توضیح بدهید‪ ،‬م ی توانید توضیحات را در باالی کد یا کنار آن بنویسید‪ .‬از توضیحات برای مستند سازی برنامه هم استفاده می شود‪ .‬در برنامه زیر نقش‬
‫توضیحات نشان داده شده است ‪:‬‬

‫‪1: namespace CommentsDemo‬‬


‫{ ‪2:‬‬
‫‪3:‬‬ ‫‪class Program‬‬
‫‪4:‬‬ ‫{‬
‫‪5:‬‬ ‫)‪public static void Main(string[] args‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫‪// This line will print the message hello world‬‬
‫‪8:‬‬ ‫;)"!‪System.Console.WriteLine("Hello World‬‬
‫‪9:‬‬ ‫}‬
‫‪10:‬‬ ‫}‬
‫} ‪11:‬‬

‫!‪Hello World‬‬
‫در کد باال‪ ،‬خط ‪ 7‬یک توضیح درباره خط ‪ 8‬است که به کاربر اعالم می کند که وظیفه خط ‪ 8‬چیست ؟ با اجرای کد باال فقط جمله ‪ Hello World‬چاپ شده‬
‫و خط ‪ 7‬در خروجی نمایش داده نمی شود چون کامپایلر توضیحات را نادیده می گیرد‪ .‬توضیحات بر سه نوعند ‪:‬‬

‫توضیحات تک خطی‬ ‫•‬

‫•‬ ‫‪// single line comment‬‬

‫توضیحات چند خطی‬ ‫•‬

‫•‬ ‫‪/* multi‬‬


‫•‬ ‫‪line‬‬
‫•‬ ‫‪comment */‬‬

‫توضیحات ‪XML‬‬ ‫•‬

‫•‬
‫•‬ ‫>‪/// <summary‬‬
‫•‬ ‫‪/// This is XML comments‬‬
‫‪35‬‬
‫•‬ ‫>‪/// </summary‬‬

‫توضیحات تک خطی همانگونه که از نامش پیداست‪ ،‬برای توضیحاتی در حد یک خط به کار می روند‪ .‬این توضیحات با عالمت ‪ //‬شروع می شوند و هر نوشته‬
‫ای که در سمت راست آن قرار بگیرد جز توضیحات به حساب می آید‪ .‬این نوع توضیحات معموال در باال یا کنار کد قرار می گیرند‪ .‬اگر توضیح درباره یک کد به‬
‫بیش از یک خط نیاز باشد از توضیحات چند خطی استفاده می شود‪ .‬توضیحات چند خطی با *‪ /‬شروع و با ‪ */‬پایان می یابند‪ .‬هر نوشته ای که بین این دو‬
‫عالمت قرار بگیرد جز توضیحات محسوب می شود‪ .‬نوع دیگری از توضیحات ‪ ،‬توضیحات ‪ XML‬نامیده می شوند‪ .‬این نوع با سه اسلش (‪ )///‬نشان داده می‬
‫شوند‪ .‬از این نوع برای مستند سازی برنامه استفاده می شود و در درس های آینده در مورد آنها توضیح خواهیم داد‪.‬‬

‫کاراکترهای کنترلی‬

‫کاراکترهای کنترلی کاراکترهای ترکیبی هستند که با یک بک اسلش (\) شروع میشوند و به دنبال آنها یک حرف یا عدد میآید و یک رشته را با فرمت خاص‬
‫نمایش میدهند‪ .‬برای مثال برای ایجاد یک خط جدید و قرار دادن رشته در آن میتوان از کاراکتر کنترلی ‪ \n‬استفاده کرد ‪:‬‬

‫;)"!‪System.Console.WriteLine("Hello\nWorld‬‬

‫‪Hello‬‬
‫‪World‬‬
‫مشاهده کردید که کامپایلر بعد از مواجهه با کاراکتر کنترلی ‪ \n‬نشانگر ماوس را به خط بعد برده و بقیه رشته را در خط بعد نمایش میدهد‪ .‬متد )(‪WriteLine‬‬
‫هم مانند کاراکتر کنترلی ‪ \n‬یک خط جدید ایجاد میکند‪ ،‬البته بدین صورت که در انتهای رشته یک کاراکتر کنترلی ‪ \n‬اضافه میکند ‪:‬‬

‫;)"!‪System.Console.WriteLine("Hello World‬‬

‫کد باال و کد زیر هیچ فرقی با هم ندارند ‪:‬‬

‫;)"‪System.Console.Write("Hello World!\n‬‬

‫متد )(‪ Write‬کارکردی شبیه به )(‪ WriteLine‬دارد با این تفاوت که نشانگر ماوس را در همان خط نگه میدارد و خط جدید ایجاد نمیکند‪ .‬جدول زیر‬
‫لیست کاراکترهای کنترلی و کارکرد آنها را نشان میدهد ‪:‬‬
‫کاراکتر کنترلی عملکرد‬ ‫کاراکتر کنترلی عملکرد‬

‫‪Form Feed‬‬ ‫‪\f‬‬ ‫چاپ کوتیشن‬ ‫’\‬

‫خط جدید‬ ‫چاپ دابل کوتیشن ‪\n‬‬ ‫”\‬

‫سر سطر رفتن‬ ‫‪\r‬‬ ‫چاپ بک اسلش‬ ‫\\‬

‫حرکت به صورت افقی‬ ‫چاپ فضای خالی ‪\t‬‬ ‫‪\0‬‬

‫حرکت به صورت عمودی‬ ‫‪\v‬‬ ‫صدای بیپ‬ ‫‪\a‬‬

‫چاپ کاراکتر یونیکد‬ ‫‪\u‬‬ ‫حرکت به عقب‬ ‫‪\b‬‬

‫‪36‬‬
‫ما برای استفاده از کاراکترهای کنترلی از بک اسلش (\) استفاده میکنیم‪ .‬از آنجاییکه \ معنای خاصی به رشتهها میدهد برای چاپ بک اسلش (\) باید از (\\)‬
‫استفاده کنیم ‪:‬‬

‫;)"‪System.Console.WriteLine("We can print a \\ by using the \\\\ escape sequence.‬‬

‫‪We can print a \ by using the \\ escape sequence.‬‬


‫یکی از موارد استفاده از \\‪ ،‬نشان دادن مسیر یک فایل در ویندوز است ‪:‬‬

‫;)"‪System.Console.WriteLine("C:\\Program Files\\Some Directory\\SomeFile.txt‬‬

‫‪C:\Program Files\Some Directory\SomeFile.txt‬‬

‫از آنجاییکه از دابل کوتیشن (“) برای نشان دادن رشتهها استفاده میکنیم برای چاپ آن از ”\ استفاده میکنیم ‪:‬‬

‫;)"‪System.Console.WriteLine("I said, \"Motivate yourself!\".‬‬

‫‪I said, "Motivate yourself!".‬‬


‫همچنین برای چاپ کوتیشن (‘) از ’\ استفاده میکنیم ‪:‬‬

‫;)"‪System.Console.WriteLine("The programmer\'s heaven.‬‬

‫‪The programmer's heaven.‬‬


‫برای ایجاد فاصله بین حروف یا کلمات از ‪ \t‬استفاده میشود ‪:‬‬

‫;)"‪System.Console.WriteLine("Left\tRight‬‬

‫‪Left‬‬ ‫‪Right‬‬

‫هر تعداد کاراکتر که بعد از کاراکتر کنترلی ‪ \r‬بیایند به اول سطر منتقل و جایگزین کاراکترهای موجود میشوند ‪:‬‬

‫;)"‪System.Console.WriteLine("Mitten\rK‬‬

‫‪Kitten‬‬

‫مثالً در مثال باال کاراکتر ‪ K‬بعد از کاراکتر کنترلی ‪ \r‬آمده است‪ .‬کاراکتر کنترلی حرف ‪ K‬را به ابتدای سطر برده و جایگزین حرف ‪ M‬میکند‪ .‬برای چاپ‬
‫کاراکترهای یونیکد میتوان از ‪ \u‬استفاده کرد‪ .‬برای استفاده از ‪ ،\u‬مقدار در مبنای ‪ 16‬کاراکتر را درست بعد از عالمت ‪ \u‬قرار میدهیم‪ .‬برای مثال اگر بخواهیم‬
‫عالمت کپی رایت (©) را چاپ کنیم‪ ،‬باید بعد از عالمت ‪ \u‬مقدار ‪ A900‬را قرار دهیم مانند ‪:‬‬

‫;)"‪System.Console.WriteLine("\u00A9‬‬

‫©‬

‫عالمت @‬

‫عالمت @ به شما اجازه میدهد که کاراکترهای کنترلی را رد کرده و رشتهای خواناتر و طبیعیتر ایجاد کنید‪ .‬وقتی از کاراکترهای کنترلی در یک رشته استفاده‬
‫میشود ممکن است برای تایپ مثالً یک بک اسلش ( \ ) به جای استفاده از دو عالمت \\ از یک \ استفاده کرده و دچار اشتباه شوید‪ .‬این کار باعث به وجود‬
‫آمدن خطای کامپایلری شده و چون کامپایلر فکر میکند که شما میخواهید یک کاراکتر کنترلی را تایپ کنید و کاراکتر بعد از عالمت \ را پردازش میکند و چون‬
‫کاراکتر کنترلی وجود ندارد خطا به وجود میآید‪.‬‬

‫‪37‬‬
‫به مثال زیر توجه کنید ‪:‬‬

‫‪System.Console.WriteLine("I want to have a cat\dog as a birthday present."); //Error‬‬

‫با وجودیکه بهتر است در مثال باال از اسلش ( ‪ ) /‬در ‪ cat/dog‬استفاده شود ولی عمداً از بک اسلش ( \ ) برای اثبات گفته باال استفاده کردهایم‪ .‬کامپایلر خطا‬
‫ایجاد میکند و به شما میگوید که کاراکتر کنترلی ‪ \d‬قابل تشخیص نیست چون همچین کاراکتر کنترلی وجود ندارد‪ .‬زمانی وضعیت بدتر خواهد شد که کاراکتر‬
‫بعد از بک اسلش کاراکتری باشد که هم جز یک کلمه باشد و هم جز کاراکترهای کنترلی‪ .‬به مثال زیر توجه کنید ‪:‬‬

‫;)"‪System.Console.WriteLine("Answer with yes\no:‬‬

‫‪Answer with yes‬‬


‫‪o‬‬

‫استفاده از عالمت @ برای نادیده گرفتن کاراکترهای کنترلی‬

‫استفاده از عالمت @ زمانی مناسب است که شما نمیخواهید از عالمت بک اسلش برای نشان دادن یک کارکتر کنترلی استفاده کنید‪ .‬استفاده از این عالمت‬
‫بسیار ساده است و کافی است که قبل از رشته مورد نظر آن را قرار دهید‪.‬‬

‫;)"‪System.Console.WriteLine(@"I want to have a cat\dog as a birthday present.‬‬

‫‪I want to have a cat\dog as a birthday present.‬‬

‫از عالمت @ معموالً زمانی استفاده می شود که شما بخواهید مسیر یک دایرکتوری را به عنوان رشته داشته باشید‪ .‬چون دایرکتوریها دارای تعداد زیادی بک‬
‫اسلش هستند و طبیعتاً استفاده از عالمت @ به جای دابل بک اسلش (\\) بهتر است‪.‬‬

‫;)"‪System.Console.WriteLine(@"C:\Some Directory\SomeFile.txt‬‬

‫‪C:\Some Directory\SomeFile.txt‬‬

‫اگر بخواهید یک دابل کوتیشن چاپ کنید به سادگی میتوانید از دو دابل کوتیشن استفاده کنید‪.‬‬

‫;)"‪System.Console.WriteLine(@"Printing ""double quotations""...‬‬

‫‪Printing "double quotations"...‬‬

‫از به کار بردن عالمت @ و کاراکترهای کنترلی به طور همزمان خودداری کنید چون باعث چاپ کاارکتر کنترلی در خروجی میشود‪.‬‬

‫استفاده از عالمت @ برای نگهداری از قالب بندی رشتهها‬

‫یکی دیگر از موارد استفاده از عالمت @ چاپ رشتههای چند خطی بدون استفاده از کاراکتر کنترلی ‪ \n‬است‪ .‬به عنوان مثال برای چاپ پیغام زیر ‪:‬‬

‫‪C# is a great programming language and‬‬


‫‪it allows you to create different‬‬
‫‪kinds of applications.‬‬

‫‪38‬‬
‫یکی از راههای چاپ جمله باال به صورت زیر است ‪:‬‬

‫‪Console.WriteLine("C# is a great programming language and\n" +‬‬


‫‪"it allows you to create different\n" +‬‬
‫;)"‪"kinds of applications.‬‬

‫به نحوه استفاده از ‪ \n‬در آخر هر جمله توجه کنید‪ .‬این کاراکتر همانطور که قبالً مشاهده کردید خط جدید ایجاد میکند و در مثال باال باعث میشود که جمله به‬
‫چند خط تقسیم شود‪ .‬از عالمت ‪ +‬هم برای ترکیب رشتهها استفاده میشود‪ .‬راه دیگر برای نمایش مثال باال در چندین خط استفاده از عالمت @ است‬

‫‪Console.WriteLine(@"C# is a great programming language and‬‬


‫‪it allows you to create different‬‬
‫;)"‪kinds of applications.‬‬

‫در این حالت کافیست که در هر جا که میخواهید رشته در خط بعد نمایش داده شود دکمه ‪ Enter‬را فشار دهید‬

‫متغیرها‬
‫متغیر مکانی از حافظه است که شما میتوانید مقادیری را در آن ذخیره کنید‪ .‬میتوان آن را به عنوان یک ظرف تصور کرد که دادههای خود را در آن قرار دادهاید‪.‬‬
‫محتویات این ظرف میتواند پاک شود یا تغییر کند‪ .‬هر متغیر دارای یک نام نیز هست‪ .‬که از طریق آن میتوان متغیر را از دیگر متغیرها تشخیص داد و به مقدار‬
‫آن دسترسی پیدا کرد‪ .‬همچنین دارای یک مقدار میباشد که میتواند توسط کاربر انتخاب شده باشد یا نتیجه یک محاسبه باشد‪ .‬مقدار متغیر میتواند تهی نیز‬
‫باشد‪ .‬متغیر دارای نوع نیز هست بدین معنی که نوع آن با نوع دادهای که در آن ذخیره میشود یکی است‪ .‬متغیر دارای عمر نیز هست که از روی آن میتوان‬
‫تشخیص داد که متغیر باید چقدر در طول برنامه مورد استفاده قرار گیرد‪ .‬و در نهایت متغیر دارای محدوده استفاده نیز هست که به شما میگوید که متغیر در چه‬
‫جای برنامه برای شما قابل دسترسی است‪ .‬ما از متغیرها به عنوان یک انبار موقتی برای ذخیره داده استفاده میکنیم‪ .‬هنگامی که یک برنامه ایجاد میکنیم احتیاج‬
‫به یک مکان برای ذخیره داده‪ ،‬مقادیر یا دادههایی که توسط کاربر وارد میشوند‪ ،‬داریم‪ .‬این مکان‪ ،‬همان متغیر است‪ .‬برای این از کلمه متغیر استفاده میشود‬
‫چون ما می توانیم بسته به نوع شرایط هر جا که الزم باشد‪ ،‬مقدار آن را تغییر دهیم‪ .‬متغیرها موقتی هستند و فقط موقعی مورد استفاده قرار میگیرند که برنامه در‬
‫حال اجراست و وقتی شما برنامه را میبندید محتویات متغیرها نیز پاک میشود‪ .‬قبالً ذکر شد که به وسیله نام متغیر میتوان به آن دسترسی پیدا کرد‪ .‬برای‬
‫نامگذاری متغیرها باید قوانین زیر را رعایت کرد ‪:‬‬

‫نام متغیر باید با یک از حروف الفبا (‪ )a-z or A-Z‬شروع شود‪.‬‬ ‫‪.1‬‬


‫نمیتواند شامل کاراکترهای غیرمجاز مانند ‪ #, ?, ^, $.‬باشد‪.‬‬ ‫‪.2‬‬
‫نمیتوان از کلمات رزرو شده در سی شارپ برای نام متغیر استفاده کرد‪.‬‬ ‫‪.3‬‬
‫نام متغیر نباید دارای فضای خالی (‪ )spaces‬باشد‪.‬‬ ‫‪.4‬‬
‫اسامی متغیرها نسبت به بزرگی و کوچکی حروف حساس هستند‪ .‬در سی شارپ دو حرف مانند ‪ a‬و ‪ A‬دو کاراکتر مختلف به حساب میآیند‪.‬‬ ‫‪.5‬‬

‫دو متغیر با نامهای ‪ myNumber‬و ‪ MyNumber‬دو متغیر مختلف محسوب میشوند چون یکی از آنها با حرف کوچک ‪ m‬و دیگری با حرف بزرگ ‪M‬‬
‫شروع میشود‪ .‬شما نمیتوانید دو متغیر را که دقیق شبیه هم هستند را در یک ‪( scope‬محدوده) تعریف کنید‪ Scope.‬به معنای یک بلوک کد است که متغیر‬
‫در آن قابل دسترسی و استفاده است‪ .‬در مورد ‪ Scope‬در فصلهای آینده بیشتر توضیح خواهیم داد‪ .‬متغیر دارای نوع هست که نوع دادهای را که در خود ذخیره‬
‫میکند را نشان میدهد‪ .‬معمولترین انواع داده ‪ int, double, string, char, float, decimal‬میباشند‪ .‬برای مثال شما برای قرار دادن یک عدد‬
‫صحیح در متغیر باید از نوع ‪ int‬استفاده کنید‪.‬‬

‫لیست کلمات کلیدی سی شارپ‬


‫‪39‬‬
‫ در زیر لیست کامل این کلمات‬.‫زبان سی شارپ دارای چندین کلمه کلیدی رزرو شده می باشد که نمی توان از آنها در نامگذاری شناسه ها و متغیرها استفاده کرد‬
:‫امده است‬

bool base as abstract

catch case byte break

const class checked char

delegate default decimal continue

enum else double do

false extern explicit event

for float fixed finally

implicit if goto foreach

interface int in (generic modifier) in

long lock is internal

object null new namespace

override out (generic modifier) out operator

public protected private params

sbyte return ref readonly

stackalloc sizeof short sealed

switch struct string static

try true throw this

unchecked ulong uint typeof

using static using ushort unsafe

while volatile void virtual

: ‫در جدول زیر هم لیست کلمات کلیدی وابسته ذکر شده که در زمان ها و مکان های خاص مانند کلمات کلیدی رفتار می کنند‬

40
‫‪ascending‬‬ ‫‪alias‬‬ ‫‪add‬‬

‫‪descending‬‬ ‫‪await‬‬ ‫‪async‬‬

‫‪get‬‬ ‫‪from‬‬ ‫‪dynamic‬‬

‫‪into‬‬ ‫‪group‬‬ ‫‪global‬‬

‫‪nameof‬‬ ‫‪let‬‬ ‫‪join‬‬

‫)‪partial (method‬‬ ‫)‪partial (type‬‬ ‫‪orderby‬‬

‫‪set‬‬ ‫‪select‬‬ ‫‪remove‬‬

‫)‪when (filter condition‬‬ ‫‪var‬‬ ‫‪value‬‬

‫)‪yield where (query clause) where (generic type constraint‬‬

‫انواع ساده‬

‫انواع ساده انواعی از دادهها هستند که شامل اعداد‪ ،‬کاراکترها و رشتهها و مقادیر بولی میباشند‪ .‬به انواع ساده انواع اصلی نیز گفته میشود چون از آنها برای‬
‫ساخت انواع پیچیدهتری مانند کالسها و ساختارها استفاده می شود‪ .‬انواع ساده دارای مجموعه مشخصی از مقادیر هستند و محدوده خاصی از اعداد را در خود‬
‫ذخیره میکنند‪ .‬در جدول زیر انواع ساده و محدود آنها آمده است ‪:‬‬
‫دامنه‬ ‫نوع‬

‫‪ sbyte‬اعداد صحیح بین ‪ -128‬تا ‪127‬‬

‫‪ byte‬اعداد صحیح بین ‪ 0‬تا ‪255‬‬

‫‪ short‬اعداد صحیح بین ‪ -32768‬تا ‪32767‬‬

‫‪ ushort‬اعداد صحیح بین ‪ 0‬تا ‪65535‬‬

‫اعداد صحیح بین ‪ -2147483648‬تا ‪2147483647‬‬ ‫‪int‬‬

‫اعداد صحیح بین ‪ 0‬تا ‪4294967295‬‬ ‫‪uint‬‬

‫‪ long‬اعداد صحیح بین ‪ -9223372036854775808‬تا ‪922337203685477807‬‬

‫‪ ulong‬اعداد صحیح بین ‪ 0‬تا ‪18446744073709551615‬‬

‫‪41‬‬
‫به حرف ‪ u‬در ابتدای برخی از انواع دادهها مثالً ‪ ushort‬توجه کنید‪ .‬این بدان معناست که این نوع فقط شامل اعداد مثبت و صفر هستند‪ .‬جدول زیر انواعی که‬
‫مقادیر با ممیز اعشار را میتوانند در خود ذخیره کنند را نشان میدهد ‪:‬‬
‫دقت‬ ‫دامنه تقریبی‬ ‫نوع‬

‫‪7‬رقم‬ ‫‪±1.5 x 10−45 to ±3.4 x 1038‬‬ ‫‪float‬‬

‫‪15 – 16‬رقم‬ ‫‪±5.0 × 10−324 to ±1.7 × 10308 double‬‬

‫‪28 – 29 ±1.0 x 10-28 to ±7.9228 x 1028 decimal‬رقم معنادار‬

‫برای به خاطر سپردن آنها باید از نماد علمی استفاده شود‪ .‬نوع دیگری از انواع ساده برای ذخیره دادههای غیر عددی به کار میروند و در جدول زیر نمایش داده‬
‫شدهاند ‪:‬‬
‫مقادیر مجاز‬ ‫نوع‬

‫‪ char‬کاراکترهای یونیکد‬

‫‪ bool‬مقدار ‪ true‬یا‪false‬‬

‫‪ string‬مجموعهای از کاراکترهای‬

‫نوع ‪ char‬برای ذخیره کاراکترهای یونیکد استفاده میشود‪ .‬کاراکترها باید داخل یک کوتیشن ساده قرار بگیرند مانند (’‪.)‘a‬‬
‫نوع ‪ bool‬فقط میتواند مقادیر درست (‪ )true‬یا نادرست (‪ )false‬را در خود ذخیره کند و بیشتر در برنامههایی که دارای ساختار تصمیم گیری هستند مورد‬
‫میگیرد‪.‬‬ ‫قرار‬ ‫استفاده‬
‫نوع ‪ string‬برای ذخیره گروهی از کاراکترها مانند یک پیغام استفاده میشود‪ .‬مقادیر ذخیره شده در یک رشته باید داخل دابل کوتیشن قرار گیرند تا توسط‬
‫کامپایلر به عنوان یک رشته در نظر گرفته شوند‪ .‬مانند (”‪)“massage‬‬

‫استفاده از متغیرها‬

‫در مثال زیر نحوه تعریف و مقداردهی متغیرها نمایش داده شده است ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫‪//Declare variables‬‬
‫‪8:‬‬ ‫;‪int num1‬‬
‫‪9:‬‬ ‫;‪int num2‬‬
‫‪10:‬‬ ‫;‪double num3‬‬
‫‪11:‬‬ ‫;‪double num4‬‬
‫‪12:‬‬ ‫;‪bool boolVal‬‬

‫‪42‬‬
13: char myChar;
14: string message;
15:
16: //Assign values to variables
17: num1 = 1;
18: num2 = 2;
19: num3 = 3.54;
20: num4 = 4.12;
21: boolVal = true;
22: myChar = 'R';
23: message = "Hello World!";
24:
25: //Show the values of the variables
26: Console.WriteLine("num1 = {0}", num1);
27: Console.WriteLine("num2 = {0}", num2);
28: Console.WriteLine("num3 = {0}", num3);
29: Console.WriteLine("num4 = {0}", num4);
30: Console.WriteLine("boolVal = {0}", boolVal);
31: Console.WriteLine("myChar = {0}", myChar);
32: Console.WriteLine("message = {0}", message);
33: }
34: }

num1 = 1
num2 = 2
num3 = 3.54
num4 = 4.12
boolVal = true
myChar = R
message = Hello World!

‫تعریف متغیر‬

‫ ابتدا باید نوع دادههایی را که این متغیرها قرار است در خود ذخیره کنند را مشخص کنیم و سپس‬.‫ متغیرهایی با نوع و نام متفاوت تعریف شدهاند‬8-14 ‫در خطوط‬
.‫ همیشه به یاد داشته باشید که قبل از مقدار دهی و استفاده از متغیر باید آن را تعریف کرد‬.‫یک نام برای آنها در نظر بگیریم و در آخر سیمیکولن بگذاریم‬

int num1;
int num2;
double num3;
double num4;
bool boolVal;
char myChar;
string message;

: ‫نحوه تعریف متغیر به صورت زیر است‬

data_type identifier;

43
‫ثابت ها‬

‫ثابتها‪ ،‬انواعی از متغیرها هستند که مقدار آنها در طول برنامه تغییر نمیکند‪ .‬ثابتها حتماً باید مقدار دهی اولیه شوند و اگر مقدار دهی آنها فراموش شود در‬
‫برنامه خطا به وجود میآید‪ .‬بعد از این که به ثابتها مقدار اولیه اختصاص داده شد هرگز در زمان اجرای برنامه نمیتوان آن را تغییر داد‪ .‬برای تعریف ثابتها باید‬
‫از کلمه کلیدی ‪ const‬استفاده کرد‪ .‬معموالً نام ثابتها را طبق قرارداد با حروف بزرگ مینویسند تا تشخیص آنها در برنامه راحت باشد‪ .‬نحوه تعریف ثابت در زیر‬
‫آمده است ‪:‬‬

‫;‪const data_type identifier = initial_value‬‬

‫مثال ‪:‬‬

‫‪class Program‬‬
‫{‬
‫)(‪public static void Main‬‬
‫{‬
‫;‪const int NUMBER = 1‬‬

‫‪NUMBER = 10; //ERROR, Cant modify a constant‬‬


‫}‬
‫}‬

‫در این مثال می بینید که مقدار دادن به یک ثابت‪ ،‬که قبالً مقدار دهی شده برنامه را با خطا مواجه میکند‪ .‬نکتهی دیگری که نباید فراموش شود این است که‬
‫داد‪.‬‬ ‫قرار‬ ‫برابر‬ ‫برنامه‬ ‫در‬ ‫شده‬ ‫تعریف‬ ‫متغیرهای‬ ‫دیگر‬ ‫مقدار‬ ‫با‬ ‫را‬ ‫ثابت‬ ‫مقدار‬ ‫نباید‬
‫مثال ‪:‬‬

‫;‪int someVariable‬‬
‫;‪const int MY_CONST = someVariable‬‬

‫ممکن است این سؤال برایتان پیش آمده باشد که دلیل استفاده از ثابتها چیست؟ اگر مطمئن هستید که مقادیری در برنامه وجود دارند که هرگز در طول برنامه‬
‫تغییر نمیکنند بهتر است که آنها را به صورت ثابت تعریف کنید‪ .‬این کار هر چند کوچک کیفیت برنامه شما را باال میبرد‪.‬‬

‫تبدیل ضمنی‬

‫تبدیل ضمنی متغیرها یک نوع تبدیل است که به طور خودکار توسط کامپایلر انجام میشود‪ .‬یک متغیر از یک نوع داده میتواند به طور ضمنی به یک نوع دیگر‬
‫تبدیل شود به شرطی که مقدار آن از مقدار دادهای که میخواهد به آن تبدیل شود کمتر باشد‪ .‬به عنوان مثال نوع دادهای ‪ byte‬میتواند مقادیر ‪ 0‬تا ‪ 255‬را در‬
‫خود ذخیره کند و نوع دادهای ‪ int‬مقادیر ‪ -2147483648‬تا ‪ 2147483647‬را شامل میشود‪ .‬پس میتوانید یک متغیر از نوع ‪ byte‬را به یک نوع ‪ int‬تبدیل‬
‫کنید ‪:‬‬

‫;‪byte number1 = 5‬‬

‫;‪int number2 = number1‬‬

‫‪44‬‬
‫در مثال باال مقدار ‪ number1‬برابر ‪ 5‬است در نتیجه متغیر ‪ number2‬که یک متغیر از نوع صحیح است میتواند مقدار ‪ number1‬را در خود ذخیره کند‬
‫چون نوع صحیح از نوع بایت بزرگتر است‪ .‬پس متغیر ‪ number1‬که یک متغیر از نوع بایت است میتواند به طور ضمنی به ‪ number2‬که یک متغیر از نوع‬
‫صحیح است تبدیل شود‪ .‬اما عکس مثال باال صادق نیست‪.‬‬

‫‪int‬‬ ‫;‪number1 = 5‬‬

‫;‪byte number2 = number1‬‬

‫در این مورد ما با خطا مواجه میشویم‪ .‬اگر چه مقدار ‪ 5‬متغیر ‪ number1‬در محدوده مقادیر ‪ byte‬یعنی اعداد بین ‪ 0-255‬قرار دارد اما متغیری از نوع بایت‬
‫حافظه کمتری نسبت به متغیری از نوع صحیح اشغال میکند‪ .‬نوع ‪ byte‬شامل ‪ 8‬بیت یا ‪ 8‬رقم دودویی است در حالی که نوع ‪ int‬شامل ‪ 32‬بیت یا رقم باینری‬
‫است‪ .‬یک عدد باینری عددی متشکل از ‪ 0‬و ‪ 1‬است‪ .‬برای مثال عدد ‪ 5‬در کامپیوتر به عدد باینری ‪ 101‬ترجمه میشود‪ .‬بنابراین وقتی ما عدد ‪ 5‬را در یک متغیر‬
‫از نوع بایت ذخیره میکنیم عددی به صورت زیر نمایش داده میشود ‪:‬‬

‫‪00000101‬‬

‫و وقتی آن را در یک متغیر از نوع صحیح ذخیره میکنیم به صورت زیر نمایش داده میشود ‪:‬‬

‫‪00000000000000000000000000000101‬‬

‫بنابراین قرار دادن یک مقدار ‪ int‬در یک متغیر ‪ byte‬درست مانند این است که ما سعی کنیم که یک توپ فوتبال را در یک سوراخ کوچک گلف جای دهیم‪.‬‬
‫برای قرار دادن یک مقدار ‪ int‬در یک متغیر از نوع ‪ byte‬میتوان از تبدیل صریح استفاده کرد که در درسهای آینده توضیح داده میشود‪ .‬نکته دیگری که نباید‬
‫فراموش شود این است که شما نمیتوانید اعداد با ممیز اعشار را به یک نوع ‪ int‬تبدیل کنید چون این کار باعث از بین رفتن بخش اعشاری این اعداد میشود‪.‬‬

‫;‪double number1 = 5.25‬‬

‫‪int number2 = number1; //Error‬‬

‫میتوان یک نوع کاراکتر را به نوع ‪ ushort‬تبدیل کرد چون هر دو دارای طیف مشابهی از اعداد هستند‪ .‬گرچه هر یک از آنها کامالً متفاوت توسط کامپایلر‬
‫ترجمه میشوند‪ .‬نوع ‪ char‬به عنوان یک کاراکتر و نوع ‪ ushort‬به عنوان یک عدد ترجمه میشود‪.‬‬

‫;'‪char charVar = 'c‬‬


‫;‪ushort shortVar = charVar‬‬

‫;)‪Console.WriteLine(charVar‬‬
‫;)‪Console.WriteLine(shortVar‬‬

‫‪c‬‬
‫‪99‬‬
‫تبدیالتی که کامپایلر به صورت ضمنی میتواند انجام دهد در جدول زیر آمده است ‪:‬‬
‫نوع منبع توانایی تبدیل امن به‬

‫‪short, ushort, int, uint, long, ulong, float, double, decimal‬‬ ‫‪byte‬‬

‫‪short, int, long, float, double, decimal sbyte‬‬

‫‪int, long, float, double, decimal short‬‬

‫‪45‬‬
‫نوع منبع توانایی تبدیل امن به‬

‫‪int, uint, long, ulong, float, double, decimal ushort‬‬

‫‪long, float, double, decimal‬‬ ‫‪int‬‬

‫‪long, ulong, float, double, decimal‬‬ ‫‪uint‬‬

‫‪float, double, decimal‬‬ ‫‪long‬‬

‫‪float, double, decimal ulong‬‬

‫‪double float‬‬

‫‪ushort, int, uint, long, ulong, float, double, decimal‬‬ ‫‪char‬‬

‫نکتهای دیگر که معموالً ابهام بر انگیز است تعین نوع داده است‪ .‬برای مثال ما چطور بدانیم که مثالً عدد ‪ 7‬از نوع ‪ long،uint ،int‬یا ‪ ulong‬است؟ برای‬
‫این کار باید کاراکترهایی را به انتهای اعداد اضافه کنیم‪.‬‬

‫;‪uint number1 = 7U‬‬


‫;‪long number2 = 7L‬‬
‫;‪ulong number3 = 7UL‬‬

‫در حالت پیشفرض و بدون قرار دادن کاراکتر در انتهای عدد کامپایلر عدد را از نوع صحیح (‪ )int‬در نظر میگیرد‪ .‬همچنین در حالت پیشفرض کامپایلر اعداد‬
‫دسیمال (‪ )decimal‬را اعداد ‪ double‬در نظر میگیرد‪ .‬شما میتوانید برای نشان دادن اعداد اعشاری ‪ float‬از کاراکتر ‪ F‬و برای نشان دادن اعداد دسیمال از‬
‫کاراکتر ‪ M‬استفاده کنید‪.‬‬

‫;‪double number1 = 1.23‬‬


‫;‪float number2 = 1.23F‬‬

‫;‪decimal number3 = 1.23M‬‬

‫تبدیل صریح‬

‫تبدیل صریح‪ ،‬نوعی تبدیل است که‪ ،‬برنامه را مجبور میکند که یک نوع داده را به نوعی دیگر تبدیل کند‪ ،‬اگر این نوع تبدیل از طریق تبدیل ضمنی انجام نشود‪.‬‬
‫در هنگام استفاده از این تبدیل باید دقت کرد چون در این نوع تبدیل ممکن است مقادیر اصالح یا حذف شوند‪ .‬ما میتوانیم این عملیات را با استفاده از ‪Cast‬‬
‫انجام دهیم‪ Cast .‬فقط نام دیگر تبدیل صریح است و دستور آن به صورت زیر است ‪:‬‬

‫;‪datatypeA variableA = value‬‬


‫;‪datatypeB variableB = (datatypeB)variableA‬‬

‫همانطور که قبالً مشاهده کردید نوع ‪ int‬را نتوانستیم به نوع ‪ byte‬تبدیل کنیم اما اکنون با استفاده از عمل ‪ Cast‬این تبدیل انجام خواهد شد ‪:‬‬

‫;‪int number1 = 5‬‬

‫;‪byte number2 = (byte)number1‬‬

‫‪46‬‬
‫حال اگر برن امه را اجرا کنید با خطا مواجه نخواهید شد‪ .‬همانطور که پیشتر اشاره شد ممکن است در هنگام تبدیالت مقادیر اصلی تغییر کنند‪ .‬برای مثال وقتی که‬
‫یک عدد با ممیز اعشار مثالً از نوع ‪ double‬را به یک نوع ‪ int‬تبدیل میکنیم مقدار اعداد بعد از ممیز از بین میروند ‪:‬‬

‫;‪double number1 = 5.25‬‬

‫;‪int number2 = (int)number1‬‬

‫;)‪Console.WriteLine(number2‬‬

‫‪5‬‬
‫خروجی کد باال عدد ‪ 5‬است چون نوع دادهای ‪ int‬نمی تواند مقدار اعشار بگیرد‪ .‬حالت دیگر را تصور کنید‪ .‬اگر شما بخواهید یک متغیر را که دارای مقداری بیشتر‬
‫از محدوده متغیر مقصد هست تبدیل کنید چه اتفاقی می افتد؟ مانند تبدیل زیر که میخواهیم متغیر ‪ number1‬را که دارای مقدار ‪ 300‬است را به نوع بایت‬
‫تبدیل کنیم که محدود اعداد بین ‪ 0-255‬را پوشش میدهد‪.‬‬

‫;‪int number1 = 300‬‬

‫;‪byte number2 = (byte)number1‬‬

‫;)‪Console.WriteLine("Value of number2 is {0}.", number2‬‬

‫‪Value of number2 is 44.‬‬


‫خروجی کد باال عدد ‪ 44‬است‪ Byte .‬فقط میتواند شامل اعداد ‪ 0‬تا ‪ 255‬باشد و نمیتواند مقدار ‪ 300‬را در خود ذخیره کند‪ .‬حال میخواهیم ببینیم که چرا به‬
‫جای عدد ‪ 300‬ما عدد ‪ 44‬را در خروجی میگیریم‪ .‬این کار به تعداد بیتها بستگی دارد‪ .‬یک ‪ byte‬دارای ‪ 8‬بیت است درحالی که ‪ int‬دارای ‪ 32‬بیت است‪ .‬حال‬
‫اگر به مقدار باینری ‪ 2‬عدد توجه کنید متوجه میشوید که چرا خروجی عدد ‪ 44‬است‪.‬‬

‫‪300 = 00000000000000000000000100101100‬‬
‫= ‪255‬‬ ‫‪11111111‬‬
‫= ‪44‬‬ ‫‪00101100‬‬

‫خروجی باال نشان میدهد که بیشترین مقدار ‪ byte‬که عدد ‪ 255‬است میتواند فقط شامل ‪ 8‬بیت باشد (‪ )11111111‬بنابراین فقط ‪ 8‬بیت اول مقدار ‪ int‬به‬
‫متغیر ‪ byte‬انتقال مییابد که شامل (‪ )00101100‬یا عدد ‪ 44‬در مبنای ‪ 10‬است‪ .‬قرار ندادن یک مقدار مناسب در داخل یک متغیر باعث ایجاد یک سرریز‬
‫(‪ )overflow‬میشود‪ .‬یک مورد آن سرریز ریاضی نام دارد که در مثال زیر مشاهده میکنید ‪:‬‬

‫;)‪byte sum = (byte)(150 + 150‬‬

‫گرچه در این تبدیل‪ ،‬ما دادههایی را از دست میدهیم‪ ،‬اما کامپایلر کد ما را قبول میکند‪ .‬برای اینکه برنامه هنگام وقوع سرریز پیغام خطا بدهد میتوان از کلمه‬
‫کلیدی ‪ checked‬استفاده کرد‪.‬‬

‫;‪int number1 = 300‬‬

‫;)‪byte number2 = checked((byte)number1‬‬

‫;)‪Console.WriteLine("Value of number2 is {0}.", number2‬‬

‫‪Unhandled Exception: System.OverflowException: Arithmetic operation resulted in an overflow ...‬‬


‫برنامه پیغام ‪ System.OverflowException‬که به زبان ساده نشان دهند وقوع خطاست‪ .‬در نتیجه شما میتوانید از اجرای برنامه جلوگیری کنید‪.‬‬

‫‪47‬‬
‫تبدیل با استفاده از کالس ‪Convert‬‬

‫کالس ‪ Convert‬یک کالس استاتیک است که میتوان از آن برای تبدیل مقادیر از نوعی به نوع دیگر استفاده کرد‪ .‬این کالس به نوبه خود دارای متدهایی‬
‫برای تبدیل انواع داده به یکدیگر میباشد‪ .‬در جدول زیر متدها ذکر شدهاند ‪:‬‬

‫نتیجه‬ ‫دستور‬

‫)‪Val Convert.ToBoolean(val‬به ‪ bool‬تبدیل میشود‬

‫‪Val‬به ‪ byte‬تبدیل میشود‬ ‫)‪Convert.ToByte(val‬‬

‫‪Val‬به ‪ char‬تبدیل میشود‬ ‫)‪Convert.ToChar(val‬‬

‫)‪Val Convert.ToDecimal(val‬به ‪ decimal‬تبدیل میشود‬

‫)‪Val Convert.ToDouble(val‬به ‪ double‬تبدیل میشود‬

‫‪Val‬به ‪ short‬تبدیل میشود‬ ‫)‪Convert.ToInt16(val‬‬

‫‪Val‬به ‪ int‬تبدیل میشود‬ ‫)‪Convert.ToInt32(val‬‬

‫‪Val‬به ‪ long‬تبدیل میشود‬ ‫)‪Convert.ToInt64(val‬‬

‫‪Val‬به ‪ sbyte‬تبدیل میشود‬ ‫)‪Convert.ToSByte(val‬‬

‫‪Val‬به ‪ float‬تبدیل میشود‬ ‫)‪Convert.ToSingle(val‬‬

‫‪Val‬به ‪ string‬تبدیل میشود‬ ‫)‪Convert.ToString(val‬‬

‫)‪Val Convert.ToUInt16(val‬به ‪ ushort‬تبدیل میشود‬

‫)‪Val Convert.ToUInt32(val‬به ‪ uint‬تبدیل میشود‬

‫)‪Val Convert.ToUInt64(val‬به ‪ ulong‬تبدیل میشود‬

‫در برنامه زیر یک نمونه از تبدیل متغیرها با استفاده از کالس ‪ Convert‬و متدهای آن نمایش داده شده است ‪:‬‬

‫;‪double x = 9.99‬‬
‫;)‪int convertedValue = Convert.ToInt32(x‬‬

‫‪48‬‬
‫;)‪Console.WriteLine("Original value is: " + x‬‬
‫;)‪Console.WriteLine("Converted value is: " + convertedValue‬‬

‫‪Original value is: 9.99‬‬


‫‪Converted value is: 10‬‬
‫مقدار ‪ val‬هر نوع دادهای میتواند باشد اما باید مطمئن شد که به نوع دادهای مورد نظر تبدیل شود‪.‬‬

‫عبارات و عملگرها‬

‫ابتدا با دو کلمه آشنا شوید ‪:‬‬

‫عملگر‪ :‬نمادهایی هستند که اعمال خاص انجام میدهند‪.‬‬ ‫•‬


‫عملوند‪ :‬مقادیری که عملگرها بر روی آنها عملی انجام میدهند‪.‬‬ ‫•‬

‫مثالً ‪ X+Y:‬یک عبارت است که در آن ‪ X‬و ‪ Y‬عملوند و عالمت ‪ +‬عملگر به حساب میآیند‪.‬‬
‫زبانهای برنامه نویسی جدید دارای عملگرهایی هستند که از اجزاء معمول زبان به حساب میآیند‪ .‬سی شارپ دارای عملگرهای مختلفی از جمله عملگرهای‬
‫ریاضی‪ ،‬تخصیصی‪ ،‬مقایسهای‪ ،‬منطقی و بیتی میباشد‪ .‬از عملگرهای ساده ریاضی میتوان به عملگر جمع و تفریق اشاره کرد‪.‬‬
‫سه نوع عملگر در سی شارپ وجود دارد ‪:‬‬

‫یگانی (‪ – )Unary‬به یک عملوند نیاز دارد‬ ‫•‬


‫دودویی (‪ – )Binary‬به دو عملوند نیاز دارد‬ ‫•‬
‫سه تایی (‪ – )Ternary‬به سه عملوند نیاز دارد‬ ‫•‬

‫انواع مختلف عملگر که در این بخش مورد بحث قرار میگیرند‪ ،‬عبارتند از ‪:‬‬

‫عملگرهای ریاضی‬ ‫•‬


‫عملگرهای تخصیصی‬ ‫•‬
‫عملگرهای مقایسهای‬ ‫•‬
‫عملگرهای منطقی‬ ‫•‬
‫عملگرهای بیتی‬ ‫•‬

‫عملگرهای ریاضی‬
‫سی شارپ از عملگرهای ریاضی برای انجام محاسبات استفاده میکند‪ .‬جدول زیر عملگرهای ریاضی سی شارپ را نشان میدهد ‪:‬‬
‫نتیجه‬ ‫مثال‬ ‫عملگر دسته‬

‫‪49‬‬
‫نتیجه‬ ‫مثال‬ ‫عملگر دسته‬

‫‪Var1 var1 = var2 + var3; Binary‬برابر است با حاصل جمع ‪ var2‬و ‪var3‬‬ ‫‪+‬‬

‫‪Var1 var1 = var2 – var3; Binary‬برابر است با حاصل تفریق ‪ var2‬و ‪var3‬‬ ‫–‬

‫‪Var1 var1 = var2 * var3; Binary‬برابر است با حاصلضرب ‪ var2‬در ‪var3‬‬ ‫*‬

‫‪Var1 var1 = var2 / var3; Binary‬برابر است با حاصل تقسیم ‪ var2‬بر ‪var3‬‬ ‫‪/‬‬

‫‪Var1 var1 = var2 % var3; Binary‬برابر است با باقیمانده تقسیم ‪ var2‬و ‪var3‬‬ ‫‪%‬‬

‫‪Var1‬برابر است با مقدار ‪var2‬‬ ‫‪var1 = +var2; Unary‬‬ ‫‪+‬‬

‫‪Var1‬برابر است با مقدار ‪ var2‬ضربدر ‪- 1‬‬ ‫‪var1 = -var2 Unary‬‬ ‫–‬

‫مثال باال در از نوع عددی استفاده شده است‪ .‬اما استفاده از عملگرهای ریاضی برای نوع رشتهای نتیجه متفاوتی دارد‪ .‬همچنین در جمع دو کاراکتر کامپایلر معادل‬
‫عددی آنها را نشان میدهد‪ .‬اگر از عملگر ‪ +‬برای رشتهها استفاده کنیم دو رشته را با هم ترکیب کرده و به هم میچسباند‪ .‬دیگر عملگرهای سی شارپ‬
‫عملگرهای کاهش و افزایش هستند‪ .‬این عملگرها مقدار ‪ 1‬را از متغیرها کم یا به آنها اضافه میکنند‪ .‬از این متغیرها اغلب در حلقهها استفاده میشود ‪:‬‬

‫نتیجه‬ ‫مثال‬ ‫عملگر دسته‬

‫‪ var1 = ++var2; Unary ++‬ابتدا به ‪ var2‬یک واحد اضافه می شود و سپس این مقدار در داخل ‪ var1‬قرار می گیرد ‪.‬‬

‫– – ‪ var1 = – -var2; Unary‬ابتدا از ‪ var2‬یک واحد کم می شود و سپس این مقدار در داخل ‪ var1‬قرار می گیرد ‪.‬‬

‫‪ var1 = var2++; Unary ++‬ابتدا مقدار ‪ var2‬در داخل ‪ var1‬قرار می گیرد و سپس یک واحد به ‪ var2‬اضافه می شود ‪.‬‬

‫‪ var1 = var2–; Unary‬ابتدا مقدار ‪ var2‬در داخل ‪ var1‬قرار می گیرد و سپس یک واحد از ‪ var2‬کم می شود ‪.‬‬ ‫—‬

‫به این نکته توجه داشته باشید که محل قرار گیری عملگر در نتیجه محاسبات تأثیر دارد‪ .‬اگر عملگر قبل از متغیر ‪ var2‬بیاید افزایش یا کاهش ‪ var1‬اتفاق می‬
‫افتد‪ .‬چنانچه عملگرها بعد از متغیر ‪ var2‬قرار بگیرند ابتدا ‪ var1‬برابر ‪ var2‬میشود و سپس متغیر ‪ var2‬افزایش یا کاهش مییابد‪.‬‬

‫به مثالهای زیر توجه کنید ‪:‬‬

‫•‬ ‫;‪using System‬‬

‫‪50‬‬

• namespace ConsoleApplication5
• {
• class Program
• {
• static void Main(string[] args)
• {
• int x = 0;
• int y = 1;

• x = ++y;

• Console.WriteLine("x= {0}",x);
• Console.WriteLine("y= {0}", y);
• Console.ReadLine();
• }
• }
• }

• x=2
• y=2

• using System;

• namespace ConsoleApplication5
• {
• class Program
• {
• static void Main(string[] args)
• {
• int x = 0;
• int y = 1;

• x = --y;

• Console.WriteLine("x= {0}",x);
• Console.WriteLine("y= {0}", y);
• Console.ReadLine();
• }
• }
• }

• x=0
• y=0
y ‫ کم و یا یک واحد به‬y ‫ باعث میشود که ابتدا یک واحد از‬y ‫ قبل از عملوند‬++ ‫ درج عملگرهای — و‬،‫همانطور که در دو مثال باال مشاهده میکنید‬
: ‫ حال به دو مثال زیر توجه کنید‬.‫ قرار بگیرد‬x ‫اضافه شود و سپس نتیجه در عملوند‬

• using System;

• namespace ConsoleApplication5
• {
• class Program
• {
• static void Main(string[] args)

51
• {
• int x = 0;
• int y = 1;

• x = y--;

• Console.WriteLine("x= {0}",x);
• Console.WriteLine("y= {0}", y);
• Console.ReadLine();
• }
• }
• }

• x=1
• y=0

• using System;

• namespace ConsoleApplication5
• {
• class Program
• {
• static void Main(string[] args)
• {
• int x = 0;
• int y = 1;

• x = y++;

• Console.WriteLine("x= {0}",x);
• Console.WriteLine("y= {0}", y);
• Console.ReadLine();
• }
• }
• }

• x=1
• y=2

‫ قرار بگیرد و‬x ‫ در داخل متغیر‬y ‫ باعث میشود که ابتدا مقدار‬y ‫ بعد از عملوند‬++ ‫ درج عملگرهای — و‬،‫همانطور که در دو مثال باال مشاهده میکنید‬
: ‫ حال میتوانیم با ایجاد یک برنامه نحوه عملکرد عملگرهای ریاضی در سی شارپ را یاد بگیریم‬.‫ کم و یا یک واحد به ان اضافه شود‬y ‫سپس یک واحد از‬

• 1: using System;
• 2:
• 3: public class Program
• 4: {
• 5: public static void Main()
• 6: {
• 7: //Variable declarations
• 8: int num1, num2;
• 9: string msg1, msg2;
• 10:

52
‫•‬ ‫‪11:‬‬ ‫‪//Assign test values‬‬
‫•‬ ‫‪12:‬‬ ‫;‪num1 = 5‬‬
‫•‬ ‫‪13:‬‬ ‫;‪num2 = 3‬‬
‫•‬ ‫‪14:‬‬
‫•‬ ‫‪15:‬‬ ‫‪//Demonstrate use of mathematical operators‬‬
‫•‬ ‫‪16:‬‬ ‫;))‪Console.WriteLine("The sum of {0} and {1} is {2}.", num1, num2, (num1 + num2‬‬
‫•‬ ‫‪17:‬‬ ‫‪Console.WriteLine("The difference of {0} and {1} is {2}.", num1, num2,‬‬
‫•‬ ‫‪18:‬‬ ‫;))‪(num1 - num2‬‬
‫•‬ ‫‪19:‬‬ ‫‪Console.WriteLine("The product of {0} and {1} is {2}.", num1, num2,‬‬
‫•‬ ‫‪20:‬‬ ‫;))‪(num1 * num2‬‬
‫•‬ ‫‪21:‬‬ ‫‪Console.WriteLine("The quotient of {0} and {1} is {2:F2}.", num1, num2,‬‬
‫•‬ ‫‪22:‬‬ ‫;))‪((double)num1 / num2‬‬
‫•‬ ‫‪23:‬‬ ‫‪Console.WriteLine("The remainder of {0} divided by {1} is {2}", num1, num2,‬‬
‫•‬ ‫‪24:‬‬ ‫;))‪(num1 % num2‬‬
‫•‬ ‫‪25:‬‬
‫•‬ ‫‪26:‬‬ ‫‪//Demonstrate concatenation on strings using the + operator‬‬
‫•‬ ‫‪27:‬‬ ‫;" ‪msg1 = "Hello‬‬
‫•‬ ‫‪28:‬‬ ‫;"!‪msg2 = "World‬‬
‫•‬ ‫‪29:‬‬ ‫;)‪Console.WriteLine(msg1 + msg2‬‬
‫•‬ ‫‪30:‬‬ ‫}‬
‫•‬ ‫} ‪31:‬‬

‫•‬ ‫‪The sum of 5 and 3 is 8.‬‬


‫•‬ ‫‪The difference of 5 and 3 is 2.‬‬
‫•‬ ‫‪The product of 5 and 3 is 15.‬‬
‫•‬ ‫‪The quotient of 5 and 3 is 1.67.‬‬
‫•‬ ‫‪The remainder of 5 divided by 3 is 2‬‬
‫•‬ ‫!‪Hello World‬‬

‫برنامه باال نتیجه هر عبارت را نشان میدهد‪ .‬در این برنامه از متد )(‪ Writeline‬برای نشان دادن نتایج در سطرهای متفاوت استفاده شده است‪ .‬در این‬
‫مثال با یک نکته عجیب مواجه میشویم و آن حاصل تقسیم دو عدد صحیح است‪ .‬وقتی که دو عدد صحیح را بر هم تقسیم کنیم حاصل باید یک عدد‬
‫صحیح و فاقد بخش کسری باشد‪ .‬اما همانطور که مشاهده میکنید اگر فقط یکی از اعداد را به نوع اعشاری ‪ double‬تبدیل کنیم (در مثال میبینید)‬
‫میشود‪.‬‬ ‫داده‬ ‫نشان‬ ‫اعشار‬ ‫صورت‬ ‫به‬ ‫حاصل‬
‫برای اینکه ارقام کسری بعد از عدد حاصل دو رقم باشند از }‪ {2:F2‬استفاده میکنیم‪ F .‬به معنای تعیین کردن میباشد و در این جا بدین معناست که‬
‫عدد را تا دو رقم اعشار نمایش بده‪ .‬چون خطوط کد طوالنی هستند آنها را در دو خط مینویسیم‪ .‬سی شارپ خط جدید و فاصله و فضای خالی را نادیده‬
‫میگیرد‪ .‬در خط ‪ 29‬مشاهده میکنید که دو رشته به وسیله عملگر ‪ +‬به هم متصل شدهاند‪ .‬نتیجه استفاده از عملگر ‪ +‬برای چسباندن دو کلمه “‪ “ Hello‬و‬
‫“!‪ ”World‬رشته “!‪ ”Hello World‬خواهد بود‪ .‬به فاصلههای خالی بعد از اولین کلمه توجه کنید اگر آنها را حذف کنید از خروجی برنامه نیز حذف‬
‫میشوند‪.‬‬

‫عملگرهای تخصیصی ( جایگزینی)‬

‫نوع دیگر از عم لگرهای سی شارپ عملگرهای جایگزینی نام دارند‪ .‬این عملگرها مقدار متغیر سمت راست خود را در متغیر سمت چپ قرار میدهند‪ .‬جدول زیر‬
‫انواع عملگرهای تخصیصی در سی شارپ را نشان میدهد‪:‬‬

‫‪53‬‬
‫نتیجه‬ ‫عملگر مثال‬

var2 ‫ برابر است با مقدار‬var1 ‫ مقدار‬var1 = var2; =

var2 ‫ و‬var1 ‫ برابر است با حاصل جمع‬var1 ‫ مقدار‬var1 += var2; +=

var2 ‫ و‬var1 ‫ برابر است با حاصل تفریق‬var1 ‫ مقدار‬var1 -= var2; -=

var2 ‫ در‬var1 ‫ برابر است با حاصل ضرب‬var1 ‫ مقدار‬var1 *= var2; *=

var2 ‫ بر‬var1 ‫ برابر است با حاصل تقسیم‬var1 ‫ مقدار‬var1 /= var2; /=

var2 ‫ بر‬var1 ‫ برابر است با باقیمانده تقسیم‬var1 ‫ مقدار‬var1 %= var2; %=

var1 ‫ مثالً شکل اصلی کد‬.‫ استفاده از این نوع عملگرها در واقع یک نوع خالصه نویسی در کد است‬.‫ برای اتصال دو رشته نیز می توان استفاده کرد‬+= ‫از عملگر‬
‫ برنامه زیر‬.‫ این حالت کدنویسی زمانی کارایی خود را نشان میدهد که نام متغیرها طوالنی باشد‬.‫ میباشد‬var1 = var1 + var2 ‫ به صورت‬+= var2
.‫چگونگی استفاده از عملگرهای تخصیصی و تأثیر آنها را بر متغیرها نشان میدهد‬

using System;

public class Program


{
public static void Main()
{
int number;

Console.WriteLine("Assigning 10 to number...");
number = 10;
Console.WriteLine("Number = {0}", number);

Console.WriteLine("Adding 10 to number...");
number += 10;
Console.WriteLine("Number = {0}", number);

Console.WriteLine("Subtracting 10 from number...");


number -= 10;
Console.WriteLine("Number = {0}", number);
}
}

Assigning 10 to number...
Number = 10
Adding 10 to number...
Number = 20
Subtracting 10 from number...
54
‫‪Number = 10‬‬

‫در برنامه از ‪ 3‬عملگر تخصیصی استفاده شده است‪ .‬ابتدا یک متغیر و مقدار ‪ 10‬با استفاده از عملگر = به آن اختصاص داده شده است‪ .‬سپس به آن با استفاده از‬
‫عملگر =‪ +‬مقدار ‪ 10‬اضافه شده است‪ .‬و در آخر به وسیله عملگر =‪ -‬عدد ‪ 10‬از آن کم شده است‪.‬‬

‫عملگرهای مقایسه ای‬

‫از عملگرهای مقایسهای برای مقایسه مقادیر استفاده میشود‪ .‬نتیجه این مقادیر یک مقدار بولی (منطقی) است‪ .‬این عملگرها اگر نتیجه مقایسه دو مقدار درست‬
‫باشد مقدار ‪ true‬و اگر نتیجه مقایسه اشتباه باشد مقدار ‪ false‬را نشان میدهند‪ .‬این عملگرها به طور معمول در دستورات شرطی به کار میروند به این ترتیب‬
‫که باعث ادامه یا توقف دستور شرطی میشوند‪ .‬جدول زیر عملگرهای مقایسهای در سی شارپ را نشان میدهد‪:‬‬
‫نتیجه‬ ‫مثال‬ ‫عملگر دسته‬

‫‪var1 var1 = var2 == var3‬در صورتی ‪ true‬است که مقدار ‪ var2‬با مقدار ‪ var3‬برابر باشد در غیر اینصورت ‪ false‬است‬ ‫== ‪Binary‬‬

‫‪var1‬در صورتی ‪ true‬است که مقدار ‪ var2‬با مقدار ‪ var3‬برابر نباشد در غیر اینصورت ‪false‬‬
‫‪var1 = var2 != var3‬‬ ‫‪Binary‬‬ ‫=!‬
‫است‬

‫‪var1‬در صورتی ‪ true‬است که مقدار ‪ var2‬کوچکتر از ‪ var3‬مقدار باشد در غیر اینصورت ‪false‬‬
‫‪var1 = var2 < var3‬‬ ‫‪Binary‬‬ ‫<‬
‫است‬

‫‪var1‬در صورتی ‪ true‬است که مقدار ‪ var2‬بزرگتر ازمقدار ‪ var3‬باشد در غیر اینصورت ‪false‬‬
‫‪var1 = var2 > var3‬‬ ‫‪Binary‬‬ ‫>‬
‫است‬

‫‪var1‬در صورتی ‪ true‬است که مقدار ‪ var2‬کوچکتر یا مساوی مقدار ‪ var3‬باشد در غیر اینصورت‬
‫‪var1 = var2 <= var3‬‬ ‫=< ‪Binary‬‬
‫‪false‬است‬

‫‪var1‬در صورتی ‪ true‬است که مقدار ‪ var2‬بزرگتر یا مساوی ‪ var3‬مقدار باشد در غیر اینصورت‬
‫‪var1 = var2 >= var3‬‬ ‫=> ‪Binary‬‬
‫‪false‬است‬

‫برنامه زیر نحوه عملکرد ای عملگرها را نشان میدهد ‪:‬‬

‫;‪using System‬‬

‫‪namespace ComparisonOperators‬‬
‫{‬
‫‪class Program‬‬
‫{‬
‫)(‪static void Main‬‬
‫‪55‬‬
‫{‬
‫;‪int num1 = 10‬‬
‫;‪int num2 = 5‬‬

‫;)‪Console.WriteLine("{0} == {1} : {2}", num1, num2, num1 == num2‬‬


‫;)‪Console.WriteLine("{0} != {1} : {2}", num1, num2, num1 != num2‬‬
‫< }‪Console.WriteLine("{0‬‬ ‫;)‪{1} : {2}", num1, num2, num1 < num2‬‬
‫> }‪Console.WriteLine("{0‬‬ ‫;)‪{1} : {2}", num1, num2, num1 > num2‬‬
‫;)‪Console.WriteLine("{0} <= {1} : {2}", num1, num2, num1 <= num2‬‬
‫;)‪Console.WriteLine("{0} >= {1} : {2}", num1, num2, num1 >= num2‬‬
‫}‬
‫}‬
‫}‬

‫‪10 == 5 : False‬‬
‫‪10 != 5 : True‬‬
‫< ‪10‬‬ ‫‪5 : False‬‬
‫> ‪10‬‬ ‫‪5 : True‬‬
‫‪10 <= 5 : False‬‬
‫‪10 >= 5 : True‬‬

‫در مثال باال ابتدا دو متغیر را که میخواهیم با هم مقایسه کنیم را ایجاد کرده و به آنها مقادیری اختصاص میدهیم‪ .‬سپس با استفاده از یک عملگر‬
‫مقایسهای آنها را با هم مقایسه کرده و نتیجه را چاپ میکنیم‪ .‬به این نکته توجه کنید که هنگام مقایسه دو متغیر از عملگر == به جای عملگر = باید‬
‫استفاده شود‪ .‬عملگر = عملگر تخصیصی است و در عبارتی مانند ‪ x = y‬مقدار ‪ y‬را در به ‪ x‬اختصاص میدهد‪ .‬عملگر == عملگر مقایسهای است که دو‬
‫مقدار را با هم مقایسه میکند مانند ‪ x==y‬و اینطور خوانده میشود ‪ x‬برابر است با ‪y‬‬

‫عملگرهای منطقی‬

‫عملگرهای منطقی بر روی عبارات منطقی عمل می کنند و نتیجه آنها نیز یک مقدار بولی است‪ .‬از این عملگرها اغلب برای شرطهای پیچیده استفاده می شود‪.‬‬
‫همانطور که قبال یاد گرفتید مقادیر بولی می توانند ‪ false‬یا ‪ true‬باشند‪ .‬فرض کنید که ‪ var2‬و ‪ var3‬دو مقدار بولی هستند‪.‬‬
‫مثال‬ ‫دسته‬ ‫عملگر نام‬
‫;‪var1 = var2 && var3‬‬ ‫‪Binary‬‬ ‫&& منطقی‪AND‬‬
‫;‪var1 = var2 || var3‬‬ ‫‪Binary‬‬ ‫|| منطقی‪OR‬‬
‫;‪var1 = !var1‬‬ ‫‪Unary‬‬ ‫! منطقی‪NOT‬‬

‫عملگر منطقی )&&(‪AND‬‬

‫اگر مقادیر دو طرف عملگر ‪ true،AND‬باشند عملگر ‪ AND‬مقدار ‪ true‬را بر می گرداند‪ .‬در غیر اینصورت اگر یکی از مقادیر یا هر دوی آنها ‪ false‬باشند‬
‫مقدار ‪ false‬را بر می گرداند‪ .‬در زیر جدول درستی عملگر ‪ AND‬نشان داده شده است ‪:‬‬

‫‪X && Y‬‬ ‫‪Y‬‬ ‫‪X‬‬

‫‪56‬‬
‫‪X && Y‬‬ ‫‪Y‬‬ ‫‪X‬‬
‫‪true‬‬ ‫‪true‬‬ ‫‪true‬‬
‫‪false‬‬ ‫‪false‬‬ ‫‪true‬‬
‫‪false‬‬ ‫‪true‬‬ ‫‪false‬‬
‫‪false‬‬ ‫‪false‬‬ ‫‪false‬‬

‫برای درک بهتر تاثیر عملگر ‪ AND‬یاد آوری می کنم که این عملگر فقط در صورتی مقدار ‪ true‬را نشان می دهد که هر دو عملوند مقدارشان ‪ true‬باشد‪.‬در‬
‫غیر اینصورت نتیجه تمام ترکیبهای بعدی ‪ false‬خواهد شد‪ .‬استفاده از عملگر ‪ AND‬مانند استفاده از عملگرهای مقایسه ای است‪ .‬به عنوان مثال نتیجه عبارت‬
‫زیر درست (‪ )true‬است اگر سن (‪ )age‬بزرگتر از ‪ 18‬و ‪ salary‬کوچکتر از ‪ 1000‬باشد‪.‬‬

‫;)‪result = (age > 18) && (salary < 1000‬‬

‫عملگر ‪ AND‬زمانی کارامد است که ما با محدود خاصی از اعداد سرو کار داریم‪ .‬مثال عبارت ‪ 10 <= x <= 100‬بدین معنی است که ‪ x‬می تواند مقداری‬
‫شامل اعداد ‪ 10‬تا ‪ 100‬را بگیرد‪ .‬حال برای انتخاب اعداد خارج از این محدوده می توان از عملگر منطقی ‪ AND‬به صورت زیر استفاده کرد‪.‬‬

‫;)‪inRange = (number <= 10) && (number >= 100‬‬

‫عملگر منطقی )||(‪OR‬‬

‫اگر یکی یا هر دو مقدار دو طرف عملگر ‪، OR‬درست (‪ )true‬باشد‪،‬عملگر ‪ OR‬مقدار ‪ true‬را بر می گرداند‪ .‬جدول درستی عملگر ‪ OR‬در زیر نشان داده شده‬
‫است ‪:‬‬
‫‪X || Y‬‬ ‫‪Y‬‬ ‫‪X‬‬

‫‪true true true‬‬

‫‪true false true‬‬

‫‪true true false‬‬

‫‪false false false‬‬

‫در جدول باال مشاهده می کنید که عملگر ‪ OR‬در صورتی مقدار ‪ false‬را بر میگرداند که مقادیر دو طرف آن ‪ false‬باشند‪ .‬کد زیر را در نظر بگیرید‪.‬نتیجه این‬
‫کد در صورتی درست (‪ )true‬است که رتبه نهایی دانش آموز (‪ )finalGrade‬بزرگتر از ‪ 75‬یا یا نمره نهایی امتحان آن ‪ 100‬باشد‪.‬‬

‫;)‪isPassed = (finalGrade >= 75) || (finalExam == 100‬‬

‫عملگر منطقی )!(‪NOT‬‬

‫برخالف دو اپراتور ‪ OR‬و ‪ AND‬عملگر منطقی ‪ NOT‬یک عملگر یگانی است و فقط به یک عملوند نیاز دارد‪ .‬این عملگر یک مقدار یا اصطالح بولی را نفی‬
‫می کند‪ .‬مثال اگر عبارت یا مقدار ‪ true‬باشد آنرا ‪ false‬و اگر ‪ false‬باشد آنرا ‪ true‬می کند‪ .‬جدول زیر عملکرد اپراتور ‪ NOT‬را نشان می دهد ‪:‬‬
‫‪57‬‬
‫‪!X‬‬ ‫‪X‬‬

‫‪false true‬‬

‫‪true false‬‬

‫نتیجه کد زیر در صورتی درست است که ‪( age‬سن) بزرگتر یا مساوی ‪ 18‬نباشد‪.‬‬

‫;)‪isMinor = !(age >= 18‬‬

‫عملگرهای بیتی‬

‫عملگرهای بیتی به شما اجازه میدهند که شکل باینری انواع دادهها را دستکاری کنید‪ .‬برای درک بهتر این درس توصیه میشود که شما سیستم باینری و نحوه‬
‫تبدیل اعداد دهدهی به باینری را از لینک زیر یاد بگیرید ‪:‬‬
‫‪http://www.w3-farsi.com/?p=5698‬‬

‫در سیستم باینری (دودویی) که کامپیوتر از آن استفاده میکند وضعیت هر چیز یا خاموش است یا روشن‪ .‬برای نشان دادن حالت روشن از عدد ‪ 1‬و برای نشان‬
‫دادن حالت خاموش از عدد ‪ 0‬استفاده میشود‪ .‬بنابراین اعداد باینری فقط میتوانند صفر یا یک باشند‪ .‬اعداد باینری را اعداد در مبنای ‪ 2‬و اعداد اعشاری را اعداد‬
‫در مبنای ‪ 10‬می گویند‪ .‬یک بیت نشان دهنده یک رقم باینری است و هر بایت نشان دهنده ‪ 8‬بیت است‪ .‬به عنوان مثال برای یک داده از نوع ‪ int‬به ‪ 32‬بیت یا‬
‫‪ 4‬بایت فضا برای ذخیره آن نیاز داریم‪ ،‬این بدین معناست که اعداد از ‪ 32‬رقم ‪ 0‬و ‪ 1‬برای ذخیره استفاده میکنند‪ .‬برای مثال عدد ‪ 100‬وقتی به عنوان یک متغیر‬
‫از نوع ‪ int‬ذخیره میشود در کامپیوتر به صورت زیر خوانده میشود ‪:‬‬

‫‪000000000000000000000000000001100100‬‬

‫عدد ‪ 100‬در مبنای ده معادل عدد ‪ 1100100‬در مبنای ‪ 2‬است‪ .‬در اینجا ‪ 7‬رقم سمت راست نشان دهنده عدد ‪ 100‬در مبنای ‪ 2‬است و مابقی صفرهای سمت‬
‫راست برای پر کردن بیتهایی است که عدد از نوع ‪ int‬نیاز دارد‪ .‬به این نکته توجه کنید که اعداد باینری از سمت راست به چپ خوانده میشوند‪ .‬عملگرهای بیتی‬
‫سی شارپ در جدول زیر نشان داده شدهاند ‪:‬‬

‫مثال‬ ‫دسته‬ ‫عملگر نام‬


‫;‪x = y & z‬‬ ‫‪Binary‬‬ ‫بیتی‪AND‬‬ ‫&‬
‫;‪x = y | z‬‬ ‫‪Binary‬‬ ‫بیتی‪OR‬‬ ‫|‬
‫;‪x = y ^ z‬‬ ‫‪Binary‬‬ ‫بیتی‪XOR‬‬ ‫^‬
‫;‪x = ~y‬‬ ‫‪Unary‬‬ ‫بیتی‪NOT‬‬ ‫~‬
‫;‪x &= y‬‬ ‫‪Binary‬‬ ‫بیتی‪AND Assignment‬‬ ‫=&‬
‫;‪x |= y‬‬ ‫‪Binary‬‬ ‫بیتی‪OR Assignment‬‬ ‫=|‬
‫;‪x ^= y‬‬ ‫‪Binary‬‬ ‫بیتی‪XOR Assignment‬‬ ‫=^‬

‫‪58‬‬
‫عملگر بیتی )&(‪AND‬‬

‫عملگر بیتی ‪ AND‬کاری شبیه عملگر منطقی ‪ AND‬انجام میدهد با این تفاوت که این عملگر بر روی بیتها کار میکند‪ .‬اگر مقادیر دو طرف آن ‪ 1‬باشد مقدار‬
‫‪ 1‬را بر میگرداند و اگر یکی یا هر دو طرف آن صفر باشد مقدار صفر را بر میگرداند‪ .‬جدول درستی عمگر بیتی ‪ AND‬در زیر آمده است‪:‬‬

‫‪X AND Y‬‬ ‫‪Y‬‬ ‫‪X‬‬

‫‪1‬‬ ‫‪1‬‬ ‫‪1‬‬

‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬

‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬

‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬

‫در زیر نحوه استفاده از عملگر بیتی ‪ AND‬آمده است ‪:‬‬

‫;‪int result = 5 & 3‬‬

‫;)‪Console.WriteLine(result‬‬

‫‪1‬‬
‫همانطور که در مثال باال مشاهده میکنید نتیجه عملکرد عملگر ‪ AND‬بر روی دو مقدار ‪ 5‬و ‪ 3‬عدد یک میشود‪ .‬اجازه بدهید ببینیم که چطور این نتیجه را به‬
‫دست میآید‪:‬‬

‫‪5:‬‬ ‫‪00000000000000000000000000000101‬‬
‫‪3:‬‬ ‫‪00000000000000000000000000000011‬‬
‫‪------------------------------------‬‬
‫‪1:‬‬ ‫‪00000000000000000000000000000001‬‬

‫ابتدا دو عدد ‪ 5‬و ‪ 3‬به معادل باینریشان تبدیل میشوند‪ .‬از آنجاییکه هر عدد صحیح)‪ 32 (int‬بیت است از صفر برای پر کردن بیتهای خالی استفاده میکنیم‪ .‬با‬
‫استفاده از جدول درستی عملگر بیتی ‪ AND‬میتوان فهمید که چرا نتیجه عدد یک میشود‪.‬‬

‫عملگر بیتی)|(‪OR‬‬

‫اگر مقادیر دو طرف عملگر بیتی ‪ OR‬هر دو صفر باشند نتیجه صفر در غیر اینصورت ‪ 1‬خواهد شد‪ .‬جدول درستی این عملگر در زیر آمده است ‪:‬‬

‫‪X OR Y‬‬ ‫‪Y‬‬ ‫‪X‬‬


‫‪1‬‬ ‫‪1‬‬ ‫‪1‬‬
‫‪1‬‬ ‫‪0‬‬ ‫‪1‬‬
‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬
‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬

‫‪59‬‬
‫نتیجه عملگر بیتی ‪ OR‬در صورتی صفر است که عملوندهای دو طرف آن صفر باشند‪ .‬اگر فقط یکی از دو عملوند یک باشد نتیجه یک خواهد شد‪ .‬به مثال زیر‬
‫توجه کنید ‪:‬‬

‫;‪int result = 7 | 9‬‬

‫;)‪Console.WriteLine(result‬‬

‫‪15‬‬
‫وقتی که از عملگر بیتی ‪ OR‬برای دو مقدار در مثال باال (‪ 7‬و ‪ )9‬استفاده میکنیم نتیجه ‪ 15‬میشود‪ .‬حال بررسی میکنیم که چرا این نتیجه به دست آمده است؟‬

‫‪7: 00000000000000000000000000000111‬‬
‫‪9: 00000000000000000000000000001001‬‬
‫‪-----------------------------------‬‬
‫‪15: 00000000000000000000000000001111‬‬

‫با استفاده از جدول درستی عملگر بیتی ‪ OR‬میتوان نتیجه استفاده از این عملگر را تشخیص داد‪ .‬عدد ‪ 1111‬باینری معادل عدد ‪ 15‬صحیح است‪.‬‬

‫عملگر بیتی )^(‪XOR‬‬

‫جدول درستی این عملگر در زیر آمده است ‪:‬‬

‫‪X XOR Y‬‬ ‫‪Y‬‬ ‫‪X‬‬

‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬

‫‪1‬‬ ‫‪0‬‬ ‫‪1‬‬

‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬

‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬

‫در صورتیکه عملوندهای دو طرف این عملگر هر دو صفر یا هر دو یک باشند نتیجه صفر در غیر اینصورت نتیجه یک میشود‪ .‬در مثال زیر تأثیر عملگر بیتی‬
‫‪ XOR‬را بر روی دو مقدار مشاهده میکنید ‪:‬‬

‫;‪int result = 5 ^ 7‬‬

‫;)‪Console.WriteLine(result‬‬

‫‪2‬‬
‫در زیر معادل باینری اعداد باال (‪ 5‬و ‪ )7‬نشان داده شده است‪.‬‬

‫‪5: 00000000000000000000000000000101‬‬
‫‪7: 00000000000000000000000000000111‬‬
‫‪-----------------------------------‬‬
‫‪2: 00000000000000000000000000000010‬‬

‫‪60‬‬
‫با نگاه کردن به جدول درستی عملگر بیتی ‪ ،XOR‬میتوان فهمید که چرا نتیجه عدد ‪ 2‬میشود‪.‬‬

‫عملگر بیتی )~(‪NOT‬‬

‫این عملگر یک عملگر یگانی است و فقط به یک عملوند نیاز دارد‪ .‬در زیر جدول درستی این عملگر آمده است‪:‬‬
‫‪NOT X‬‬ ‫‪X‬‬
‫‪0‬‬ ‫‪1‬‬
‫‪1‬‬ ‫‪0‬‬
‫عملگر بیتی ‪ NOT‬مقادیر بیتها را معکوس میکند‪ .‬در زیر چگونگی استفاده از این عملگر آمده است ‪:‬‬

‫;‪int result = ~7‬‬

‫;)‪Console.WriteLine(result‬‬

‫به نمایش باینری مثال باال که در زیر نشان داده شده است توجه نمایید‪.‬‬

‫‪7: 00000000000000000000000000000111‬‬
‫‪------------------------------------‬‬
‫‪-8: 11111111111111111111111111111000‬‬

‫مثالهایی از عملگرهای بیتی‬

‫فرض کنید که از یک سبک خاص فونت در برنامهتان استفاده کنید‪ .‬کدهای مربوط به هر سبک هم در جدول زیر آمده است ‪:‬‬
‫کد‬ ‫سبک‬
‫‪0‬‬ ‫‪Regular‬‬
‫‪1‬‬ ‫‪Bold‬‬
‫‪2‬‬ ‫‪Italic‬‬
‫‪4‬‬ ‫‪Underline‬‬
‫‪8‬‬ ‫‪Strikeout‬‬
‫توجه کنید که مقدار اولیه صفر بدین معنی است که میخواهید از سبک ‪( regular‬عادی) استفاده کنید‪.‬‬

‫;‪int fontStyle = 0‬‬

‫برای نشان دادن فونتها به صورت کلفت (‪ )Bold‬از عملگر بیتی ‪ OR‬استفاده میشود‪ .‬توجه کنید که برای فونت ‪ Bold‬باید کد ‪ 1‬را به کار برید‪.‬‬

‫;‪fontStyle = fontStyle | 1‬‬

‫برای استفاده از سبک ‪ Italic‬باید از عملگر بیتی ‪ OR‬و کد ‪ 2‬استفاده شود‪.‬‬

‫;‪fontStyle |= 2‬‬

‫‪61‬‬
‫برای استفاده از سایر سبکها میتوان به روشهای ذکر شده در باال عمل کرد و فقط کدها را جایگزین کنید‪ .‬اگر بخواهید یک سبک جدید ایجاد کنید که ترکیبی‬
‫از چند سبک باشد میتوانید به سادگی عملگر بیتی ‪ OR‬را در بین هر سبک فونت قرار دهید مانند مثال زیر ‪:‬‬

‫;‪fontStyle = 1 | 2 | 4 | 8‬‬

‫عملگر بیتی تغییر مکان (‪)shift‬‬

‫این نوع عملگرها به شما اجازه می دهند که بیتها را به سمت چپ یا راست جا به جا کنید‪ .‬دو نوع عملگر بیتی تغییر مکان وجود دارد که هر کدام دو عملوند قبول‬
‫میکنند‪ .‬عملوند سمت چپ این عملگرها حالت باینری یک مقدار و عملوند سمت راست تعداد جابه جاییبیت ها را نشان میدهد‪.‬‬
‫مثال‬ ‫دسته‬ ‫عملگر نام‬

‫;‪x = y << 2‬‬ ‫‪Binary‬‬ ‫تغییر مکان به سمت چپ‬ ‫>>‬

‫;‪x = y >> 2‬‬ ‫‪Binary‬‬ ‫تغییر مکان به سمت راست‬ ‫<<‬

‫عملگر تغییر مکان به سمت چپ‬

‫این عملگر بیتهای عملوند سمت چپ را به تعداد ‪ n‬مکان مشخص شده توسط عملوند سمت راست‪ ،‬به سمت چپ منتقل میکند‪ .‬به عنوان مثال ‪:‬‬

‫;‪int result = 10 << 2‬‬

‫;)‪Console.WriteLine(result‬‬

‫‪40‬‬
‫در مثال باال ما بیتهای مقدار ‪ 10‬را دو مکان به سمت چپ منتقل کردهایم‪ ،‬حال بیایید تأثیر این انتقال را بررسی کنیم ‪:‬‬

‫‪10: 00000000000000000000000000001010‬‬
‫‪------------------------------------‬‬
‫‪40: 00000000000000000000000000101000‬‬

‫مشاهده میکنید که همه بیتها به اندازه دو واحد به سمت چپ منتقل شدهاند‪ .‬در این انتقال دو صفر از صفرهای سمت چپ کم میشود و در عوض دو صفر به‬
‫سمت راست اضافه میشود‪.‬‬

‫عملگر تغییر مکان به سمت راست‬

‫این عملگر شبیه به عمگر تغییر مکان به سمت چپ است با این تفاوت که بیتها را به سمت راست جا به جا میکند‪ .‬به عنوان مثال ‪:‬‬

‫;‪int result = 100 >> 4‬‬

‫;)‪Console.WriteLine(result‬‬

‫‪6‬‬
‫‪62‬‬
‫با استفاده از عملگرتغییر مکان به سمت راست بیتهای مقدار ‪ 100‬را به اندازه ‪ 4‬واحد به سمت چپ جا به جا میکنیم‪ .‬اجازه بدهید تأثیر این جا به جایی را مورد‬
‫بررسی قرار دهیم ‪:‬‬

‫‪100: 00000000000000000000000001100100‬‬
‫‪------------------------------------‬‬
‫‪6: 00000000000000000000000000000110‬‬

‫هر بیت به اندازه ‪ 4‬واحد به سمت راست منتقل میشود‪ ،‬بنابراین ‪ 4‬بیت اول سمت راست حذف شده و چهار صفر به سمت چپ اضافه میشود‪.‬‬

‫تقدم عملگرها‬

‫تقدم عملگرها مشخص میکند که در محاسباتی که بیش از دو عملوند دارند ابتدا کدام عملگر اثرش را اعمال کند‪ .‬عملگرها در سی شارپ در محاسبات دارای‬
‫حق تقدم هستند‪ .‬به عنوان مثال ‪:‬‬

‫;‪number = 1 + 2 * 3 / 1‬‬

‫اگر ما حق تقدم عملگرها را رعایت نکنیم و عبارت باال را از سمت چپ به راست انجام دهیم نتیجه ‪ 9‬خواهد شد (‪ 1+2=3‬سپس ‪ 3×3=9‬و در آخر ‪ .)9/1=9‬اما‬
‫کامپایلر با توجه به تقدم عملگرها محاسبات را انجام میدهد‪ .‬برای مثال عمل ضرب و تقسیم نسبت به جمع و تفریق تقدم دارند‪ .‬بنابراین در مثال فوق ابتدا عدد‬
‫‪ 2‬ضربدر ‪ 3‬و سپس نتیجه آنها تقسیم بر ‪ 1‬میشود که نتیجه ‪ 6‬به دست میآید‪ .‬در آخر عدد ‪ 6‬با ‪ 1‬جمع میشود و عدد ‪ 7‬حاصل میشود‪ .‬در جدول زیر تقدم‬
‫برخی از عملگرهای سی شارپ آمده است ‪:‬‬

‫عملگر‬ ‫تقدم‬

‫باالترین )‪++, –, (used as prefixes); +, – (unary‬‬

‫‪*, /, %‬‬

‫– ‪+,‬‬

‫>> ‪<<,‬‬

‫=> ‪<, >, <=,‬‬

‫=! ‪==,‬‬

‫&‬

‫‪63‬‬
‫عملگر‬ ‫تقدم‬

‫^‬

‫|‬

‫&&‬

‫||‬

‫=‪=, *=, /=, %=, +=, -‬‬

‫)‪++, — (used as suffixes‬‬ ‫پایینترین‬

‫ابتدا عملگرهای با باالترین و سپس عملگرهای با پایینترین حق تقدم در محاسبات تأثیر میگذارند‪ .‬به این نکته توجه کنید که تقدم عملگرها ‪ ++‬و – به مکان‬
‫قرارگیری آنها بستگی دارد (در سمت چپ یا راست عملوند باشند)‪ .‬به عنوان مثال ‪:‬‬

‫;‪int number = 3‬‬

‫‪number1 = 3 + ++number; //results to 7‬‬


‫‪number2 = 3 + number++; //results to 6‬‬

‫در عبارت اول ابتدا به مقدار ‪ number‬یک واحد اضافه شده و ‪ 4‬میشود و سپس مقدار جدید با عدد ‪ 3‬جمع میشود و در نهایت عدد ‪ 7‬به دست میآید‪ .‬در‬
‫عبارت دوم مقدار عددی ‪ 3‬به مقدار ‪ number‬اضافه میشود و عدد ‪ 6‬به دست میآید‪ .‬سپس این مقدار در متغیر ‪ number2‬قرار میگیرد‪ .‬و در نهایت مقدار‬
‫‪ number‬به ‪ 4‬افزایش مییابد‪ .‬برای ایجاد خوانایی در تقدم عملگرها و انجام محاسباتی که در آنها از عملگرهای زیادی استفاده میشود از پرانتز استفاده‬
‫میکنیم ‪:‬‬

‫;)) ‪number = ( 1 + 2 ) * ( 3 / 4 ) % ( 5 - ( 6 * 7‬‬

‫در مثال باال ابتدا هر کدام از عباراتی که داخل پرانتز هستند مورد محاسبه قرار میگیرند‪ .‬به نکتهای در مورد عبارتی که در داخل پرانتز سوم قرار دارد توجه کنید‪.‬‬
‫در این عبارت ابتدا مقدار داخلیترین پرانتز مورد محاسبه قرار میگیرد یعنی مقدار ‪ 6‬ضربدر ‪ 7‬شده و سپس از ‪ 5‬کم میشود‪ .‬اگر دو یا چند عملگر با حق تقدم‬
‫یکسان موجود باشد ابتدا باید هر کدام از عملگرها را که در ابتدای عبارت میآیند مورد ارزیابی قرار دهید‪ .‬به عنوان مثال ‪:‬‬

‫;‪number = 3 * 2 + 8 / 4‬‬

‫هر دو عملگر * و ‪ /‬دارای حق تقدم یکسانی هستند‪ .‬بنابر این شما باید از چپ به راست آنها را در محاسبات تأثیر دهید‪ .‬یعنی ابتدا ‪ 3‬را ضربدر ‪ 2‬میکنید و‬
‫سپس عدد ‪ 8‬را بر ‪ 4‬تقسیم میکنید‪ .‬در نهایت نتیجه دو عبارت را جمع کرده و در متغیر ‪ number‬قرار میدهید‪.‬‬

‫گرفتن ورودی از کاربر‬

‫چارچوب دات نت تعدادی متد برای گرفتن ورودی از کاربر در اختیار شما قرار میدهد‪ .‬حال میخواهیم درباره متد ()‪ ReadLine‬یکی دیگر از متدهای کالس‬
‫‪ Console‬بحث کنیم که یک مقدار رشتهای را از کاربر دریافت میکند‪ .‬متد ()‪ ReadLine‬فقط مقدار رشتهای را که توسط کاربر نوشته میشود را بر‬
‫میگرداند‪ .‬همانطور که از نام این متد پیداست‪ ،‬تمام کاراکترهایی را که شما در محیط کنسول تایپ میکنید تا زمانی که دکمه ‪ enter‬را میزنید میخواند‪ .‬هر چه‬

‫‪64‬‬
‫که در محیط کنسول تایپ میشود از نوع رشته است‪ .‬برای تبدیل نوع رشته به انواع دیگر میتوانید از کالس ‪ Convert‬و متدهای آن استفاده کنید‪ .‬به برنامه‬
‫زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪string name‬‬
‫‪8:‬‬ ‫;‪int age‬‬
‫‪9:‬‬ ‫;‪double height‬‬
‫‪10:‬‬
‫‪11:‬‬ ‫;)" ‪Console.Write("Enter your name:‬‬
‫‪12:‬‬ ‫;)(‪name = Console.ReadLine‬‬
‫‪13:‬‬ ‫;)" ‪Console.Write("Enter your age:‬‬
‫‪14:‬‬ ‫;))(‪age = Convert.ToInt32(Console.ReadLine‬‬
‫‪15:‬‬ ‫;)" ‪Console.Write("Enter your height:‬‬
‫‪16:‬‬ ‫;))(‪height = Convert.ToDouble(Console.ReadLine‬‬
‫‪17:‬‬
‫‪18:‬‬ ‫‪//Print a blank line‬‬
‫‪19:‬‬ ‫;)(‪Console.WriteLine‬‬
‫‪20:‬‬
‫‪21:‬‬ ‫‪//Show the details you typed‬‬
‫‪22:‬‬ ‫;)‪Console.WriteLine("Name is {0}.", name‬‬
‫‪23:‬‬ ‫;)‪Console.WriteLine("Age is {0}.", age‬‬
‫‪24:‬‬ ‫;)‪Console.WriteLine("Height is {0}.", height‬‬
‫‪25:‬‬ ‫}‬
‫} ‪26:‬‬

‫‪Enter your name: John‬‬


‫‪Enter your age: 18‬‬
‫‪Enter your height: 160.5‬‬

‫‪Name is John.‬‬
‫‪Age is 18.‬‬
‫‪Height is 160.5.‬‬
‫ابتدا ‪ 3‬متغیر را برای ذخیره داده در برنامه تعریف میکنیم (خطوط ‪ 7‬و ‪ 8‬و ‪ .)9‬برنامه از کاربر میخواهد که نام خود را وارد کند (خط ‪ .)11‬در خط ‪ 12‬شما به‬
‫عنوان کاربر نام خود را وارد میکنید‪ .‬مقدار متغیر نام‪ ،‬برابر مقداری است که توسط متد )(‪ ReadLine‬خوانده میشود‪ .‬از آنجاییکه نام از نوع رشته است و‬
‫مقداری که از متد )(‪ ReadLine‬خوانده میشود هم از نوع رشته است در نتیجه نیازی به تبدیل انواع نداریم‪.‬‬
‫سپس برنامه از ما سن را سؤال میکند (خط ‪ .)13‬سن‪ ،‬متغیری از نوع صحیح (‪ )int‬است‪ ،‬پس نیاز است که ما تبدیل از نوع رشته به صحیح را انجام دهیم‪.‬‬
‫بنابراین از کالس و متد )(‪ Convert.ToInt32‬برای این تبدیل استفاده میکنیم (خط ‪ .)14‬مقدار بازگشتی از این متد در متغیر سن قرار میگیرد‪ .‬چون متغیر‬
‫قد (‪ )height‬را از نوع ‪ double‬تعریف کردهایم برای تبدیل رشته دریافتی از محیط کنسول به نوع ‪ double‬باید از متد و کالس‬
‫)(‪ Convert.ToDouble‬استفاده کنیم (خط ‪ .)16‬عالوه بر آنچه گفته شد شما میتوانید از متد ()‪ parse‬برای تبدیلهای باال استفاده کنید‪ ،‬مانند‪:‬‬

‫;))(‪age = int.Parse(Console.ReadLine‬‬
‫;))(‪height = double.Parse(Console.ReadLine‬‬

‫‪65‬‬
‫توجه داشته باشد که این متد برای تبدیل رشته به رقم استفاده میشود یعنی رشتهای که توسط کاربر تایپ میشود باید فقط عدد باشد‪.‬‬

‫ساختارهای تصمیم‬

‫تقریبا همه زبانهای برنامه نویسی به شما اجازه اجرای کد را در شرایط مطمئن می دهند‪ .‬حال تصور کنید که یک برنامه دارای ساختار تصمیم گیری نباشد و همه‬
‫کدها را اجرا کند‪ .‬این حالت شاید فقط برای چاپ یک پیغام در صفحه مناسب باشد ولی فرض کنید که شما بخواهید اگر مقدار یک متغیر با یک عدد برابر باشد‬
‫سپس یک پیغام چاپ شود آن وقت با مشکل مواجه خواهید شد‪ .‬سی شارپ راه های مختلفی برای رفع این نوع مشکالت ارائه می دهد‪ .‬در این بخش با مطالب‬
‫زیر آشنا خواهید شد ‪:‬‬

‫دستور ‪if‬‬ ‫•‬


‫دستور ‪else…if‬‬ ‫•‬
‫عملگر سه تایی‬ ‫•‬
‫دستور ‪ if‬چندگانه‬ ‫•‬
‫دستور ‪ if‬تو در تو‬ ‫•‬
‫عملگرهای منطقی‬ ‫•‬
‫دستور ‪switch‬‬ ‫•‬

‫دستور ‪if‬‬
‫میتوان با استفاده از دستور ‪ if‬و یک شرط خاص که باعث ایجاد یک کد میشود یک منطق به برنامه خود اضافه کنید‪ .‬دستور ‪ if‬سادهترین دستور شرطی است‬
‫که برنامه میگوید اگر شرطی برقرار است کد معینی را انجام بده‪ .‬ساختار دستور ‪ if‬به صورت زیر است ‪:‬‬

‫•‬ ‫)‪if (condition‬‬


‫•‬ ‫;‪code to execute‬‬

‫قبل از اجرای دستور ‪ if‬ابتدا شرط بررسی میشود‪ .‬اگر شرط برقرار باشد یعنی درست باشد سپس کد اجرا میشود‪ .‬شرط یک عبارت مقایسهای است‪.‬‬
‫میتوان از عملگرهای مقایسه ای برای تست درست یا اشتباه بودن شرط استفاده کرد‪ .‬اجازه بدهید که نگاهی به نحوه استفاده از دستور ‪ if‬در داخل برنامه‬
‫بیندازیم‪ .‬برنامه زیر پیغام ‪ Hello World‬را اگر مقدار ‪ number‬کمتر از ‪ 10‬و ‪ Goodbye World‬را اگر مقدار ‪ number‬از ‪ 10‬بزرگتر باشد در‬
‫صفحه نمایش میدهد‪.‬‬

‫•‬ ‫;‪1: using System‬‬


‫•‬ ‫‪2:‬‬
‫•‬ ‫‪3: public class Program‬‬
‫•‬ ‫{ ‪4:‬‬
‫•‬ ‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫•‬ ‫‪6:‬‬ ‫{‬
‫•‬ ‫‪7:‬‬ ‫‪//Declare a variable and set it a value less than 10‬‬
‫•‬ ‫‪8:‬‬ ‫;‪int number = 5‬‬
‫•‬ ‫‪9:‬‬
‫•‬ ‫‪10:‬‬ ‫‪//If the value of number is less than 10‬‬
‫•‬ ‫‪11:‬‬ ‫)‪if (number < 10‬‬
‫•‬ ‫‪12:‬‬ ‫;)"‪Console.WriteLine("Hello World.‬‬
‫•‬ ‫‪13:‬‬
‫•‬ ‫‪14:‬‬ ‫‪//Change the value of a number to a value which‬‬

‫‪66‬‬
‫•‬ ‫‪15:‬‬ ‫‪// is greater than 10‬‬
‫•‬ ‫‪16:‬‬ ‫;‪number = 15‬‬
‫•‬ ‫‪17:‬‬
‫•‬ ‫‪18:‬‬ ‫‪//If the value of number is greater than 10‬‬
‫•‬ ‫‪19:‬‬ ‫)‪if (number > 10‬‬
‫•‬ ‫‪20:‬‬ ‫;)"‪Console.WriteLine("Goodbye World.‬‬
‫•‬ ‫‪21:‬‬ ‫}‬
‫•‬ ‫} ‪22:‬‬

‫•‬ ‫‪Hello World.‬‬


‫•‬ ‫‪Goodbye World.‬‬

‫در خط ‪ 8‬یک متغیر با نام ‪ number‬تعریف و مقدار ‪ 5‬به آن اختصاص داده شده است‪ .‬وقتی به اولین دستور ‪ if‬در خط ‪ 11‬میرسیم برنامه تشخیص میدهد که‬
‫مقدار ‪ number‬از ‪ 10‬کمتر است یعنی ‪ 5‬کوچکتر از ‪ 10‬است‪.‬‬
‫منطقی است که نتیجه مقایسه درست میباشد بنابراین دستور ‪ if‬دستور را اجرا میکند (خط ‪ )12‬و پیغام ‪ Hello World‬چاپ میشود‪ .‬حال مقدار ‪number‬‬
‫را به ‪ 15‬تغییر میدهیم (خط ‪ .)16‬وقتی به دومین دستور ‪ if‬در خط ‪ 19‬میرسیم برنامه مقدار ‪ number‬را با ‪ 10‬مقایسه میکند و چون مقدار ‪ number‬یعنی‬
‫‪ 15‬از ‪ 10‬بزرگتر است برنامه پیغام ‪ Goodbye World‬را چاپ میکند (خط ‪ .)20‬به این نکته توجه کنید که دستور ‪ if‬را میتوان در یک خط نوشت ‪:‬‬

‫•‬ ‫;)"‪if ( number > 10 ) Console.WriteLine("Goodbye World.‬‬

‫شما میتوانید چندیندستور را در داخل دستور ‪ if‬بنویسید‪ .‬کافیست که از یک آکوالد برای نشان دادن ابتدا و انتهای دستورات استفاده کنید‪ .‬همه دستورات‬
‫داخل بین آکوالد جز بدنه دستور ‪ if‬هستند‪ .‬نحوه تعریف چند دستور در داخل بدنه ‪ if‬به صورت زیر است ‪:‬‬

‫•‬ ‫)‪if (condition‬‬


‫•‬ ‫{‬
‫•‬ ‫;‪statement1‬‬
‫•‬ ‫;‪statement2‬‬
‫•‬ ‫‪.‬‬
‫•‬ ‫‪.‬‬
‫•‬ ‫‪.‬‬
‫•‬ ‫;‪statementN‬‬
‫•‬ ‫}‬

‫این هم یک مثال ساده ‪:‬‬

‫•‬ ‫)‪if (x > 10‬‬


‫•‬ ‫{‬
‫•‬ ‫;)"‪Console.WriteLine("x is greater than 10.‬‬
‫•‬ ‫;)"‪Console.WriteLine("This is still part of the if statement.‬‬
‫•‬ ‫}‬

‫در مثال باال اگر مقدار ‪ x‬از ‪ 10‬بزرگتر باشد دو پیغام چاپ میشود‪ .‬حال اگر به عنوان مثال آکوالد را حذف کنیم و مقدار ‪ x‬از ‪ 10‬بزرگتر نباشد مانند کد‬
‫زیر ‪:‬‬

‫•‬ ‫)‪if (x > 10‬‬


‫•‬ ‫;)"‪Console.WriteLine("x is greater than 10.‬‬
‫•‬ ‫;)")?‪Console.WriteLine("This is still part of the if statement. (Really‬‬

‫‪67‬‬
.‫کد باال در صورتی بهتر خوانده میشود که بین دستورات فاصله بگذاریم‬

• if (x > 10)
• Console.WriteLine("x is greater than 10.");

• Console.WriteLine("This is still part of the if statement. (Really?)");

‫ کوچکتر است پس‬10 ‫ از‬x ‫ اینجاست که چون ما فرض را بر این گذاشتهایم که مقدار‬.‫ نیست‬if ‫) در مثال باال جز دستور‬3 ‫میبیند که دستور دوم (خط‬
‫ به عنوان تمرین‬.‫ در نتیجه اهمیت وجود آکوالد مشخص میشود‬.‫ چاپ میشود‬This is still part of the if statement. (Really?)‫خط‬
‫ فراموش نکنید که از قلم انداختن یک آکوالد باعث به وجود آمدن خطا‬.‫ داشتید برای آن یک آکوالد بگذارید‬if ‫همیشه حتی اگر فقط یک دستور در بدنه‬
if ‫ یکی از خطاهای معمول کسانی که برنامه نویسی را تازه شروع کردهاند قرار دادن سیمیکولن در سمت راست پرانتز‬.‫شده و یافتن آن را سخت میکند‬
: ‫ به عنوان مثال‬.‫است‬

• if (x > 10);
• Console.WriteLine("x is greater than 10");

‫ همیشه به یاد داشته‬.‫ بنابراین برنامه شما با یک خطای منطقی مواجه میشود‬.‫ یک مقایسه را انجام میدهد و دستور اجرایی نیست‬if ‫به یاد داشته باشید که‬
: if ‫ مثالی دیگر در مورد دستور‬.‫ به منزله این است که بلوک کد در اینجا به پایان رسیده است‬if ‫باشید که قرار گرفتن سیمیکولن در سمت راست پرانتز‬

• using System;

• public class Program
• {
• public static void Main()
• {
• int firstNumber;
• int secondNumber;

• Console.Write("Enter a number: ");
• firstNumber = Convert.ToInt32(Console.ReadLine());

• Console.Write("Enter another number: ");
• secondNumber = Convert.ToInt32(Console.ReadLine());

• if (firstNumber == secondNumber)
• {
• Console.WriteLine("{0} == {1}", firstNumber, secondNumber);
• }
• if (firstNumber != secondNumber)
• {
• Console.WriteLine("{0} != {1}", firstNumber, secondNumber);
• }
• if (firstNumber < secondNumber)
• {
• Console.WriteLine("{0} < {1}", firstNumber, secondNumber);
• }
• if (firstNumber > secondNumber)
• {
• Console.WriteLine("{0} > {1}", firstNumber, secondNumber);
• }
• if (firstNumber <= secondNumber)

68
‫•‬ ‫{‬
‫•‬ ‫;)‪Console.WriteLine("{0} <= {1}", firstNumber, secondNumber‬‬
‫•‬ ‫}‬
‫•‬ ‫)‪if (firstNumber >= secondNumber‬‬
‫•‬ ‫{‬
‫•‬ ‫;)‪Console.WriteLine("{0} >= {1}", firstNumber, secondNumber‬‬
‫•‬ ‫}‬
‫•‬ ‫}‬
‫•‬ ‫}‬

‫•‬ ‫‪Enter a number: 2‬‬


‫•‬ ‫‪Enter another number: 5‬‬
‫•‬ ‫‪2 != 5‬‬
‫•‬ ‫‪2 < 5‬‬
‫•‬ ‫‪2 <= 5‬‬
‫•‬ ‫‪Enter a number: 10‬‬
‫•‬ ‫‪Enter another number: 3‬‬
‫•‬ ‫‪10 != 3‬‬
‫•‬ ‫‪10 > 3‬‬
‫•‬ ‫‪10 >= 3‬‬
‫•‬ ‫‪Enter a number: 5‬‬
‫•‬ ‫‪Enter another number: 5‬‬
‫•‬ ‫‪5 == 5‬‬
‫•‬ ‫‪5 <= 5‬‬
‫•‬ ‫‪5 >= 5‬‬

‫ما از عملگرهای مقایسهای در دستور ‪ if‬استفاده کردهایم‪ .‬ابتدا دو عدد که قرار است با هم مقایسه شوند را به عنوان ورودی از کاربر میگیریم‪ .‬اعداد با هم‬
‫مقایسه میشوند و اگر شرط درست بود پیغامی چاپ می شود‪ .‬به این نکته توجه داشته باشید که شرطها مقادیر بولی هستند‪ ،‬بنابراین شما میتوانید نتیجه‬
‫یک عبارت را در داخل یک متغیر بولی ذخیره کنید و سپس از متغیر به عنوان شرط در دستور ‪ if‬استفاده کنید‪ .‬اگر مقدار ‪ year‬برابر ‪ 2000‬باشد سپس‬
‫حاصل عبارت در متغیر ‪ isNewMillenium‬ذخیره میشود‪ .‬میتوان از متغیر برای تشخیص کد اجرایی بدنه دستور ‪ if‬استفاده کرد خواه مقدار متغیر‬
‫درست باشد یا نادرست‪.‬‬

‫•‬ ‫;‪bool isNewMillenium = year == 2000‬‬


‫•‬
‫•‬ ‫)‪if (isNewMillenium‬‬
‫•‬ ‫{‬
‫•‬ ‫;)"!‪Console.WriteLine("Happy New Millenium‬‬
‫•‬ ‫}‬

‫دستور ‪else…if‬‬

‫دستور ‪ if‬فقط برای اجرای یک حالت خاص به کار میرود یعنی اگر حالتی برقرار بود کار خاصی انجام شود‪ .‬اما زمانی که شما بخواهید اگر شرط خاصی برقرار‬
‫شد یک دستور و اگر برقرار نبود دستور دیگر اجرا شود باید از دستور ‪ if else‬استفاده کنید‪ .‬ساختار دستور ‪ if else‬در زیر آمده است ‪:‬‬

‫)‪if (condition‬‬
‫{‬
‫;‪code to execute if condition is true‬‬
‫}‬
‫‪else‬‬
‫‪69‬‬
‫{‬
‫;‪code to execute if condition is false‬‬
‫}‬

‫از کلمه کلیدی ‪ else‬نمیتوان به تنهایی استفاده کرد بلکه حتم ًا باید با ‪ if‬به کار برده شود‪ .‬اگر فقط یک کد اجرایی در داخل بدنه ‪ if‬و بدنه ‪ else‬دارید استفاده‬
‫از آکوالد اختیاری است‪ .‬کد داخل بلوک ‪ else‬فقط در صورتی اجرا میشود که شرط داخل دستور ‪ if‬نادرست باشد‪ .‬در زیر نحوه استفاده از دستور ‪if…else‬‬
‫آمده است‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪int number = 5‬‬
‫‪8:‬‬
‫‪9:‬‬ ‫‪//Test the condition‬‬
‫‪10:‬‬ ‫)‪if (number < 10‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫;)"‪Console.WriteLine("The number is less than 10.‬‬
‫‪13:‬‬ ‫}‬
‫‪14:‬‬ ‫‪else‬‬
‫‪15:‬‬ ‫{‬
‫‪16:‬‬ ‫;)"‪Console.WriteLine("The number is either greater than or equal to 10.‬‬
‫‪17:‬‬ ‫}‬
‫‪18:‬‬
‫‪19:‬‬ ‫‪//Modify value of number‬‬
‫‪20:‬‬ ‫;‪number = 15‬‬
‫‪21:‬‬
‫‪22:‬‬ ‫‪//Repeat the test to yield a different result‬‬
‫‪23:‬‬ ‫)‪if (number < 10‬‬
‫‪24:‬‬ ‫{‬
‫‪25:‬‬ ‫;)"‪Console.WriteLine("The number is less than 10.‬‬
‫‪26:‬‬ ‫}‬
‫‪27:‬‬ ‫‪else‬‬
‫‪28:‬‬ ‫{‬
‫‪29:‬‬ ‫;)"‪Console.WriteLine("The number is either greater than or equal to 10.‬‬
‫‪30:‬‬ ‫}‬
‫‪31:‬‬ ‫}‬
‫} ‪32:‬‬

‫در خط ‪ 7‬یک متغیر به نام ‪ number‬تعریف کردهایم و در خط ‪ 10‬تست میکنیم که آیا مقدار متغیر ‪ number‬از ‪ 10‬کمتر است یا نه و چون کمتر است در‬
‫نتیجه کد داخل بلوک ‪ if‬اجرا میشود (خط ‪ )12‬و اگر مقدار ‪ number‬را تغییر دهیم و به مقداری بزرگتر از ‪ 10‬تغییر دهیم (خط ‪ ،)20‬شرط نادرست میشود‬
‫(خط ‪ )23‬و کد داخل بلوک ‪ else‬اجرا میشود (خط ‪ .)29‬مانند بلوک ‪ if‬نباید به آخر کلمه کلیدی ‪ else‬سیمیکولن اضافه شود‪.‬‬

‫عملگر شرطی‬

‫عملگر شرطی (‪ )?:‬در سی شارپ مانند دستور شرطی ‪ if…else‬عمل میکند‪ .‬در زیر نحوه استفاده از این عملگر آمده است‪:‬‬

‫‪70‬‬
‫>‪<condition> ? <result if true> : <result if false‬‬

‫عملگر شرطی تنها عملگر سه تایی سی شارپ است که نیاز به سه عملوند دارد‪ ،‬شرط‪ ،‬یک مقدار زمانی که شرط درست باشد و یک مقدار زمانی که شرط‬
‫نادرست باشد‪ .‬اجازه بدهید که نحوه استفاده این عملگر را در داخل برنامه مورد بررسی قرار دهیم‪.‬‬

‫‪public class Program‬‬


‫{‬
‫)(‪public static void Main‬‬
‫{‬
‫;"‪string pet1 = "puppy‬‬
‫;"‪string pet2 = "kitten‬‬
‫;‪string type1‬‬
‫;‪string type2‬‬

‫;"‪type1 = (pet1 == "puppy" ) ? "dog" : "cat‬‬


‫;"‪type2 = (pet2 == "kitten") ? "cat" : "dog‬‬
‫}‬
‫}‬

‫برنامه باال نحوه استفاده از این عملگر شرطی را نشان میدهد‪ .‬خط یک به صورت زیر ترجمه میشود‪ :‬اگر مقدار ‪ pet1‬برابر با ‪ puppy‬سپس مقدار ‪ dog‬را در‬
‫‪ type1‬قرار بده در غیر این صورت مقدار ‪ cat‬را ‪ type1‬قرار بده‪ .‬خط دو به صورت زیر ترجمه میشود‪ :‬اگر مقدار ‪ pet2‬برابر با ‪ kitten‬سپس مقدار ‪ cat‬را‬
‫در ‪ type2‬قرار بده در غیر این صورت مقدار ‪ .dog‬حال برنامه باال را با استفاده از دستور ‪ if else‬مینویسیم‪:‬‬

‫)"‪if (pet1 == "puppy‬‬


‫;"‪type1 = "dog‬‬
‫‪else‬‬
‫;"‪type1 = "cat‬‬

‫هنگامی که چندین دستور در داخل یک بلوک ‪ if‬یا ‪ else‬دارید از عملگر شرطی استفاده نکنید چون خوانایی برنامه را پایین میآورد‪.‬‬

‫دستور ‪ if‬چندگانه‬

‫اگر بخواهید چند شرط را بررسی کنید چکار میکنید؟ میتوانید از چندین دستور ‪ if‬استفاده کنید و بهتر است که این دستورات ‪ if‬را به صورت زیر بنویسید ‪:‬‬

‫)‪if (condition‬‬
‫{‬
‫;‪code to execute‬‬
‫}‬
‫‪else‬‬
‫{‬
‫)‪if (condition‬‬
‫{‬
‫;‪code to execute‬‬
‫}‬
‫‪else‬‬
‫{‬
‫)‪if (condition‬‬
‫{‬

‫‪71‬‬
code to execute;
}
else
{
code to execute;
}
}
}

: ‫ میتوانید کد باال را سادهتر کنید‬.‫ بنویسید‬else ‫ بهتر است دستورات را به صورت تو رفتگی در داخل بلوک‬.‫خواندن کد باال سخت است‬

if (condition)
{
code to execute;
}
else if (condition)
{
code to execute;
}
else if (condition)
{
code to execute;
}
else
{
code to execute;
}

‫ وقتی اجرا میشود که‬else if ‫ دستور‬.‫ وابسته است‬if ‫ نیز به دستور‬else if ، else ‫ را یاد گرفتید باید بدانید که مانند‬else if ‫حال که نحوه استفده از دستور‬
‫ برنامه‬.‫ اجرا میشود‬else ‫ و اگر آن نیز اجرا نشود در نهایت دستور‬.‫ بعدی اجرا میشود‬else if ‫ اشتباه باشد دستور‬else if ‫ اشتباه باشد حال اگر‬if ‫اولین دستور‬
: ‫ را نشان میدهد‬if else‫زیر نحوه استفاده از دستور‬

using System;

public class Program


{
public static void Main()
{
int choice;
Console.WriteLine("What's your favorite color?");
Console.WriteLine("[1] Black");
Console.WriteLine("[2] White");
Console.WriteLine("[3] Blue");
Console.WriteLine("[4] Red");
Console.WriteLine("[5] Yellown");

Console.Write("Enter your choice: ");


choice = Convert.ToInt32(Console.ReadLine());

if (choice == 1)
{
Console.WriteLine("You might like my black t-shirt.");

72
}
else if (choice == 2)
{
Console.WriteLine("You might be a clean and tidy person.");
}
else if (choice == 3)
{
Console.WriteLine("You might be sad today.");
}
else if (choice == 4)
{
Console.WriteLine("You might be inlove right now.");
}
else if (choice == 5)
{
Console.WriteLine("Lemon might be your favorite fruit.");
}
else
{
Console.WriteLine("Sorry, your favorite color is " +
"not in the choices above.");
}
}
}

What's your favorite color?


[1] Black
[2] White
[3] Blue
[4] Red
[5] Yellow

Enter your choice: 1


You might like my black t-shirt.
What's your favorite color?
[1] Black
[2] White
[3] Blue
[4] Red
[5] Yellow

Enter your choice: 999


Sorry, your favorite color is not in the choices above.

‫ اگر عددی که شما تایپ‬.‫ بسته به اینکه شما چه چیزی انتخاب میکنید پیغامهای مختلفی چاپ میشود‬.‫ وابسته است‬choice ‫خروجی برنامه باال به متغیر‬
.‫ اجرا میشود‬else ‫میکنید در داخل حالتهای انتخاب نباشد کد مربوط به بلوک‬

‫ تو در تو‬if ‫دستور‬

.‫ دیگر‬if ‫ در داخل دستور‬if ‫ یک دستور ساده‬.‫ تو در تو در سی شارپ استفاده کرد‬if ‫میتوان از دستور‬
73
if (condition)
{
code to execute;

if (condition)
{
code to execute;
}
else if (condition)
{
if (condition)
{
code to execute;
}
}
}
else
{
if (condition)
{
code to execute;
}
}

: ‫ تو در تو را نشان دهیم‬if ‫اجازه بدهید که نحوه استفاده از دستور‬

1: using System;
2:
3: public class Program
4: {
5: public static void Main()
6: {
7: int age;
8: string gender;
9:
10: Console.Write("Enter your age: ");
11: age = Convert.ToInt32(Console.ReadLine());
12:
13: Console.Write("Enter your gender (male/female): ");
14: gender = Console.ReadLine();
15:
16: if (age > 12)
17: {
18: if (age < 20)
19: {
20: if (gender == "male")
21: {
22: Console.WriteLine("You are a teenage boy.");
23: }
24: else
25: {
26: Console.WriteLine("You are a teenage girl.");

74
‫‪27:‬‬ ‫}‬
‫‪28:‬‬ ‫}‬
‫‪29:‬‬ ‫‪else‬‬
‫‪30:‬‬ ‫{‬
‫‪31:‬‬ ‫;)"‪Console.WriteLine("You are already an adult.‬‬
‫‪32:‬‬ ‫}‬
‫‪33:‬‬ ‫}‬
‫‪34:‬‬ ‫‪else‬‬
‫‪35:‬‬ ‫{‬
‫‪36:‬‬ ‫;)"‪Console.WriteLine("You are still too young.‬‬
‫‪37:‬‬ ‫}‬
‫‪38:‬‬ ‫}‬
‫} ‪39:‬‬

‫‪Enter your age: 18‬‬


‫‪Enter your gender: male‬‬
‫‪You are a teenage boy.‬‬
‫‪Enter your age: 12‬‬
‫‪Enter your gender: female‬‬
‫‪You are still too young.‬‬
‫اجازه بدهید که برنامه را کالبد شکافی کنیم‪ .‬ابتدا برنامه از شما درباره سنتان سؤال میکند (خط ‪ .)11‬در خط ‪ 14‬درباره جنستان از شما سؤال میکند‪ .‬سپس به‬
‫اولین دستور ‪ if‬میرسد (خط ‪ .)16‬در این قسمت اگر سن شما بیشتر از ‪ 12‬سال باشد برنامه وارد بدنه دستور ‪ if‬میشود در غیر اینصورت وارد بلوک ‪(else‬خط‬
‫میشود‪.‬‬ ‫‪if‬‬ ‫دستور‬ ‫همین‬ ‫به‬ ‫مربوط‬ ‫‪)34‬‬
‫حال فرض کنیم که سن شما بیشتر از ‪ 12‬سال است و شما وارد بدنه اولین ‪ if‬شدهاید‪ .‬در بدنه اولین ‪ if‬دو دستور ‪ if‬دیگر را مشاهده میکنید‪ .‬اگر سن کمتر ‪20‬‬
‫باشد شما وارد بدنه ‪ if‬دوم میشوید و اگر نباشد به قسمت ‪ else‬متناظر با آن میروید (خط ‪ .)29‬دوباره فرض میکنیم که سن شما کمتر از ‪ 20‬باشد‪ ،‬در‬
‫اینصورت وارد بدنه ‪ if‬دوم شده و با یک ‪ if‬دیگر مواجه میشوید (خط ‪ .)20‬در اینجا جنسیت شما مورد بررسی قرار میگیرد که اگر برابر “‪ ”male‬باشد‪ ،‬کدهای‬
‫داخل بدنه سومین ‪ if‬اجرا میشود در غیر اینصورت قسمت ‪ else‬مربوط به این ‪ if‬اجرا میشود (خط ‪ .)24‬پیشنهاد میشود که از ‪ if‬تو در تو در برنامه کمتر‬
‫استفاده کنید چون خوانایی برنامه را پایین میآورد‪.‬‬

‫استفاده از عملگرهای منطقی‬

‫عملگرهای منطقی به شما اجازه میدهند که چندین شرط را با هم ترکیب کنید‪ .‬این عملگرها حداقل دو شرط را در گیر میکنند و در آخر یک مقدار بولی را بر‬
‫میگردانند‪ .‬در جدول زیر برخی از عملگرهای منطقی آمده است ‪:‬‬
‫تأثیر‬ ‫عملگر تلفظ مثال‬

‫‪ z = (x > 2) && (y‬مقدار ‪ Z‬در صورتی ‪ true‬است که هر دو شرط دو طرف عملگر مقدارشان ‪ true‬باشد‪ .‬اگر فقط مقدار یکی از شروط‬
‫&& ‪And‬‬
‫‪false‬باشد مقدار ‪z ، false‬خواهد شد ‪.‬‬ ‫)‪< 10‬‬

‫< ‪ z = (x > 2) || (y‬مقدار ‪ Z‬در صورتی ‪ true‬است که یکی از دو شرط دو طرف عملگر مقدارشان ‪ true‬باشد‪ .‬اگر هر دو شرط مقدارشان‬
‫‪Or‬‬ ‫||‬
‫‪false‬باشد مقدار ‪z ، false‬خواهد شد ‪.‬‬ ‫)‪10‬‬

‫مقدار ‪ Z‬در صورتی ‪ true‬است که مقدار شرط ‪ false‬باشد و در صورتی ‪ false‬است که مقدار شرط ‪ true‬باشد ‪.‬‬ ‫‪z = !(x > 2) Not‬‬ ‫!‬

‫به عنوان مثال جمله )‪ z = (x > 2) && (y < 10‬را به این صورت بخوانید‪“ :‬در صورتی مقدار ‪ z‬برابر ‪ true‬است که مقدار ‪ x‬بزرگتر از ‪ 2‬و مقدار ‪y‬‬
‫کوچکتر از ‪ 10‬باشد در غیر اینصورت ‪ false‬است”‪ .‬این جمله بدین معناست که برای اینکه مقدار کل دستور ‪ true‬باشد باید مقدار همه شروط ‪ true‬باشد‪.‬‬

‫‪75‬‬
‫ است اگر فقط مقدار یکی از شروط‬true ‫ برابر‬OR ‫ نتیجه عملگر منطقی‬.‫ دارد‬AND (&&) ‫ تأثیر متفاوتی نسبت به عملگر منطقی‬OR (||) ‫عملگر منطقی‬
‫ را با هم ترکیب کرده و در یک‬OR ‫ و‬AND ‫ میتوان عملگرهای منطقی‬.‫ خواهد شد‬false ‫ نباشد نتیجه‬true ‫ و اگر مقدار هیچ یک از شروط‬.‫ باشد‬true
: ‫عبارت به کار برد مانند‬

if ( (x == 1) && ( (y > 3) || z < 10) ) )


{
//do something here
}

‫( مورد بررسی قرار میگیرد‬y > 3) || (z < 10) ‫ در اینجا ابتدا عبارت‬.‫در اینجا استفاده از پرانتز مهم است چون از آن در گروه بندی شرطها استفاده میکنیم‬
‫ حال بیایید نحوه استفاده از عملگرهای منطقی در برنامه را‬.‫) مقایسه میشود‬x == 1( ‫ با نتیجه‬AND ‫ سپس نتیجه آن بوسیله عملگر‬.)‫(به علت تقدم عملگرها‬
: ‫مورد بررسی قرار دهیم‬

1: using System;
2:
3: public class Program
4: {
5: public static void Main()
6: {
7: int age;
8: string gender;
9:
10: Console.Write("Enter your age: ");
11: age = Convert.ToInt32(Console.ReadLine());
12:
13: Console.Write("Enter your gender (male/female): ");
14: gender = Console.ReadLine();
15:
16: if (age > 12 && age < 20)
17: {
18: if (gender == "male")
19: {
20: Console.WriteLine("You are a teenage boy.");
21: }
22: else
23: {
24: Console.WriteLine("You are a teenage girl.");
25: }
26: }
27: else
28: {
29: Console.WriteLine("You are not a teenager.");
30: }
31: }
32: }

Enter your age: 18


Enter your gender (male/female): female
You are a teenage girl.

76
‫‪Enter you age: 10‬‬
‫‪Enter your gender (male/female): male‬‬
‫‪You are not a teenager.‬‬

‫برنامه باال نحوه استفاده از عملگر منطقی ‪ AND‬را نشان میدهد (خط ‪ .)16‬وقتی به دستور ‪ if‬میرسید (خط ‪ )16‬برنامه سن شما را چک میکند‪ .‬اگر سن شما‬
‫بزرگتر از ‪ 12‬و کوچکتر از ‪ 20‬باشد (سنتان بین ‪ 12‬و ‪ 20‬باشد) یعنی مقدار هر دو ‪ true‬باشد سپس کدهای داخل بلوک ‪ if‬اجرا میشوند‪ .‬اگر نتیجه یکی از‬
‫شروط ‪ false‬باشد کدهای داخل بلوک ‪ else‬اجرا میشود‪ .‬عملگر ‪ AND‬عملوند سمت چپ را مرود بررسی قرار میدهد‪ .‬اگر مقدار آن ‪ false‬باشد دیگر‬
‫عملوند سمت راست را بررسی نمیکند و مقدار ‪ false‬را بر میگرداند‪ .‬بر عکس عملگر || عملوند سمت چپ را مورد بررسی قرار میدهد و اگر مقدار آن ‪true‬‬
‫باشد سپس عملوند سمت راست را نادیده میگیرد و مقدار ‪ true‬را بر میگرداند‪.‬‬

‫)‪if (x == 2 & y == 3‬‬


‫{‬
‫‪//Some code here‬‬
‫}‬

‫)‪if (x == 2 | y == 3‬‬
‫{‬
‫‪//Some code here‬‬
‫}}‬

‫نکته مهم اینجاست که شما میتوانید از عملگرهای & و | به عنوان عملگر بیتی استفاده کنید‪ .‬تفاوت جزئی این عملگرها وقتی که به عنوان عملگر بیتی به کار‬
‫می روند این است که دو عملوند را بدون در نظر گرفتن مقدار عملوند سمت چپ مورد بررسی قرار میدهند‪ .‬به عنوان مثال حتی اگر مقدار عملوند سمت چپ‬
‫‪ false‬باشد عملوند سمت چپ به وسیله عملگر بیتی )&( ‪ AND‬ارزیابی میشود‪ .‬اگر شرطها را در برنامه ترکیب کنید استفاده از عملگرهای منطقی ‪AND‬‬
‫)&&( و )||( ‪ OR‬به جای عملگرهای بیتی )&(‪ AND‬و )|( ‪ OR‬بهتر خواهد بود‪ .‬یکی دیگر از عملگرهای منطقی عملگر )!( ‪ NOT‬است که نتیجه‬
‫یک عبارت را خنثی یا منفی میکند‪ .‬به مثال زیر توجه کنید‪:‬‬

‫))‪if (!(x == 2‬‬


‫{‬
‫;)"‪Console.WriteLine("x is not equal to 2.‬‬
‫}‬

‫اگر نتیجه عبارت ‪ x == 2‬برابر ‪ false‬باشد عملگر ! آن را ‪ True‬میکند‪.‬‬

‫دستور ‪Switch‬‬

‫در سی شارپ ساختاری به نام ‪ switch‬وجود دارد که به شما اجازه میدهد که با توجه به مقدار ثابت یک متغیر چندین انتخاب داشته باشید‪ .‬دستور ‪switch‬‬
‫معادل دستور ‪ if‬تو در تو است با این تفاوت که در دستور ‪ switch‬متغیر فقط مقادیر ثابتی از اعداد‪ ،‬رشتهها و یا کاراکترها را قبول میکند‪ .‬مقادیر ثابت مقادیری‬
‫هستند که قابل تغییر نیستند‪ .‬در زیر نحوه استفاده از دستور ‪ switch‬آمده است ‪:‬‬

‫)‪switch (testVar‬‬
‫{‬
‫‪case compareVal1:‬‬
‫;‪code to execute if testVar == compareVa11‬‬
‫;‪break‬‬
‫‪case compareVa12:‬‬
‫;‪code to execute if testVar == compareVa12‬‬

‫‪77‬‬
break;
.
.
.
case compareVa1N:
code to execute if testVer == compareVa1N;
break;
default:
code to execute if none of the values above match the testVar;
break;
}

.‫ مقایسه میشود‬switch ‫ داخل بلوک‬case ‫ این مقدار با هر یک از عبارتهای‬.‫ است قرار میدهید‬testVar ‫ که در مثال باال‬switch ‫ابتدا یک مقدار در متغیر‬
‫ به این نکته توجه کنید که حتی اگر تعداد خط‬.‫ اجرا خواهد شد‬case ‫ برابر بود کد مربوط به آن‬case ‫اگر مقدار متغیر با هر یک از مقادیر موجود در دستورات‬
‫ تشخیص داده میشود که باعث‬break ‫ با کلمه کلیدی‬case ‫ آخر هر دستور‬.‫ از یکی بیشتر باشد نباید از آکوالد استفاده کنیم‬case ‫کدهای داخل دستور‬
switch ‫ دستور‬.‫ اگر این کلمه کلیدی از قلم بیوفتد برنامه با خطا مواجه میشود‬.‫ خارج شده ودستورات بعد از آن اجرا شوند‬switch ‫میشود برنامه از دستور‬
‫ اختیاری است‬default ‫ دستور‬.‫ برابر نباشد‬case ‫ این دستور در صورتی اجرا میشود که مقدار متغیر با هیچ یک از مقادیر دستورات‬.‫ دارد‬default ‫یک بخش‬
‫ به مثالی در مورد‬.‫ مکان این دستور هم مهم نیست اما بر طبق تعریف آن را در پایان دستورات مینویسند‬.‫ حذف شود هیچ اتفاقی نمیافتد‬switch ‫و اگر از بدنه‬
: ‫ توجه کنید‬switch ‫دستور‬

using System;

public class Program


{
public static void Main()
{
int choice;

Console.WriteLine("What's your favorite pet?");


Console.WriteLine("[1] Dog");
Console.WriteLine("[2] Cat");
Console.WriteLine("[3] Rabbit");
Console.WriteLine("[4] Turtle");
Console.WriteLine("[5] Fish");
Console.WriteLine("[6] Not in the choices");
Console.Write("nEnter your choice: ");

choice = Convert.ToInt32(Console.ReadLine());

switch (choice)
{
case 1:
Console.WriteLine("Your favorite pet is Dog.");
break;
case 2:
Console.WriteLine("Your favorite pet is Cat.");
break;
case 3:
Console.WriteLine("Your favorite pet is Rabbit.");
break;
case 4:

78
Console.WriteLine("Your favorite pet is Turtle.");
break;
case 5:
Console.WriteLine("Your favorite pet is Fish.");
break;
case 6:
Console.WriteLine("Your favorite pet is not in the choices.");
break;
default:
Console.WriteLine("You don't have a favorite pet.");
break;
}
}
}

What's your favorite pet?


[1] Dog
[2] Cat
[3] Rabbit
[4] Turtle
[5] Fish
[6] Not in the choices

Enter your choice: 2


Your favorite pet is Cat.
What's your favorite pet?
[1] Dog
[2] Cat
[3] Rabbit
[4] Turtle
[5] Fish
[6] Not in the choices

Enter your choice: 99


You don't have a favorite pet.

‫ شما عدد را وارد میکنید و این عدد در دستور‬.‫ به اسم هر حیوان یک عدد نسبت داده شده است‬.‫برنامه باال به شما اجازه انتخاب حیوان مورد عالقهتان را میدهد‬
‫ ها‬case ‫ اگر هم با هیچ کدام از مقادیر‬.‫ مقایسه می شود و با هر کدام از آن مقادیر که برابر بود پیغام مناسب نمایش داده خواهد شد‬case ‫ با مقادیر‬switch
‫ برای نشان داده یک مجموعه‬case ‫ این است که شما میتوانید از دو یا چند‬switch ‫ یکی دیگر از ویژگیهای دستور‬.‫ اجرا میشود‬default ‫برابر نبود دستور‬
.‫ ها باید پشت سر هم نوشته شوند‬case ‫ توجه کنید که‬.‫ باشد یک کد اجرا میشود‬3 ‫ یا‬2 ،1 ‫ عدد‬number ‫ در مثال زیر اگر مقدار‬.‫کد استفاده کنید‬

switch(number)
{
case 1:
case 2:
case 3:
Console.WriteLine("This code is shared by three values.");
break;
}

: ‫ برنامه باال را به صورت زیر نیز میتوان نوشت‬.‫ تو در تو است‬if ‫ معادل دستور‬switch ‫همانطور که قبالً ذکر شد دستور‬
79
if (choice == 1)
Console.WriteLine("Your favorite pet is Dog.");
else if (choice == 2)
Console.WriteLine("Your favorite pet is Cat.");
else if (choice == 3)
Console.WriteLine("Your favorite pet is Rabbit.");
else if (choice == 4)
Console.WriteLine("Your favorite pet is Turtle.");
else if (choice == 5)
Console.WriteLine("Your favorite pet is Fish.");
else if (choice == 6)
Console.WriteLine("Your favorite pet is not in the choices.");
else
Console.WriteLine("You don't have a favorite pet.");

‫) کدامیک را‬if else ‫ و‬switch( ‫ حال از بین این دو دستور‬.‫ میباشد‬else ‫ معادل دستور‬default ‫ دستور‬.‫ دارد‬switch ‫کد باال دقیقاً نتیجهای مانند دستور‬
switch ‫ مثالً در مثال زیر هیچگاه از‬.‫ موقعی استفاده میکنیم که مقداری که میخواهیم با دیگر مقادیر مقایسه شود ثابت باشد‬switch ‫ از دستور‬.‫انتخاب کنیم‬
.‫استفاده نکنید‬

int myNumber = 5;
int x = 5;

switch (myNumber)
{
case x:
Console.WriteLine("Error, you can't use variables as a value" +
" to be compared in a case statment.");
break;
}

‫ یک ثابت نیست بلکه‬x ‫ مقایسه شده است برنامه خطا میدهد چون‬myNumber ‫ است و به طور واضح با متغیر‬5 ‫ عدد‬x ‫مشاهده میکنید که با اینکه مقدار‬
.‫ به صورت زیر استفاده کنید‬const ‫ استفاده کنید و برنامه خطا ندهد باید از کلمه کلیدی‬x ‫ اگر بخواهید از‬.‫ قابلیت تغییر را دارد‬،‫یک متغیر است یا به زبان سادهتر‬

int myNumber = 5;
const int x = 5;

switch (myNumber)
{
case x:
Console.WriteLine("Error has been fixed!");
break;
}

‫ به یاد داشته باشید‬.‫ توجه کنید که بعد از تعریف یک ثابت نمیتوان مقدار آن را در طول برنامه تغییر داد‬.‫ برای ایجاد ثابتها استفاده میشود‬const ‫از کلمه کلیدی‬
‫ ها مقایسه میکند و شما الزم نیست که به شکل زیر مقادیر را با هم مقایسه‬case ‫ یک مقدار را با مقادیر‬switch ‫ دستور‬.‫که باید ثابتها را حتماً مقداردهی کنید‬
: ‫کنید‬

switch (myNumber)
{
case x > myNumber:
80
‫‪Console.WriteLine("switch staments can't test if a value is less than " +‬‬
‫;)"‪"or greater than the other value.‬‬
‫;‪break‬‬
‫}‬

‫تکرار‬

‫ساختارهای تکرار به شما اجازه میدهند که یک یا چند دستور کد را تا زمانی که یک شرط برقرار است تکرار کنید‪ .‬بدون ساختارهای تکرار شما مجبورید همان‬
‫تعداد کدها را بنویسید که بسیار خسته کننده است‪ .‬مثالً شما مجبورید ‪ 10‬بار جمله “‪ ”Hello World.‬را تایپ کنید مانند مثال زیر ‪:‬‬

‫;)"‪Console.WriteLine("Hello World.‬‬
‫;)"‪Console.WriteLine("Hello World.‬‬
‫;)"‪Console.WriteLine("Hello World.‬‬
‫;)"‪Console.WriteLine("Hello World.‬‬
‫;)"‪Console.WriteLine("Hello World.‬‬
‫;)"‪Console.WriteLine("Hello World.‬‬
‫;)"‪Console.WriteLine("Hello World.‬‬
‫;)"‪Console.WriteLine("Hello World.‬‬
‫;)"‪Console.WriteLine("Hello World.‬‬
‫;)"‪Console.WriteLine("Hello World.‬‬

‫البته شما می توانید با کپی کردن این تعداد کد را راحت بنویسید ولی این کار در کل کیفیت کدنویسی را پایین میآورد‪ .‬راه بهتر برای نوشتن کدهای باال استفاده از‬
‫حلقهها است‪ .‬حلقهها در سی شارپ عبارتند از ‪:‬‬

‫‪while‬‬ ‫•‬
‫‪do while‬‬ ‫•‬
‫‪for‬‬ ‫•‬
‫‪foreach‬‬ ‫•‬

‫درباره حلقه ‪ ،foreach‬بعد از مبحث آرایهها توضیح میدهیم‪.‬‬

‫حلقه ‪While‬‬

‫ابتداییترین ساختار تکرار در سی شارپ حلقه ‪ While‬است‪ .‬ابتدا یک شرط را مورد بررسی قرار میدهد و تا زمانیکه شرط برقرار باشد کدهای درون بلوک اجرا‬
‫میشوند‪ .‬ساختار حلقه ‪ While‬به صورت زیر است ‪:‬‬

‫)‪while(condition‬‬
‫{‬
‫;‪code to loop‬‬

‫‪81‬‬
‫}‬

‫میبینید که ساختار ‪ While‬مانند ساختار ‪ if‬بسیار ساده است‪ .‬ابتدا یک شرط را که نتیجه آن یک مقدار بولی است مینویسیم اگر نتیجه درست یا ‪ true‬باشد‬
‫سپس کدهای داخل بلوک ‪ While‬اجرا میشوند‪ .‬اگر شرط غلط یا ‪ false‬باشد وقتی که برنامه به حلقه ‪ While‬برسد هیچکدام از کدها را اجرا نمیکند‪ .‬برای‬
‫متوقف شدن حلقه باید مقادیر داخل حلقه ‪ While‬اصالح شوند‪.‬‬
‫به یک متغیر شمارنده در داخل بدنه حلقه نیاز داریم‪ .‬این شمارنده برای آزمایش شرط مورد استفاده قرار میگیرد و ادامه یا توقف حلقه به نوعی به آن وابسته‬
‫است‪ .‬این شمارنده را در داخل بدنه باید کاهش یا افزایش دهیم‪ .‬در برنامه زیر نحوه استفاده از حلقه ‪ While‬آمده است ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪int counter = 1‬‬
‫‪8:‬‬
‫‪9:‬‬ ‫)‪while (counter <= 10‬‬
‫‪10:‬‬ ‫{‬
‫‪11:‬‬ ‫;)"!‪Console.WriteLine("Hello World‬‬
‫‪12:‬‬ ‫;‪counter++‬‬
‫‪13:‬‬ ‫}‬
‫‪14:‬‬
‫‪15:‬‬ ‫}‬
‫} ‪16:‬‬

‫!‪Hello World‬‬
‫!‪Hello World‬‬
‫!‪Hello World‬‬
‫!‪Hello World‬‬
‫!‪Hello World‬‬
‫!‪Hello World‬‬
‫!‪Hello World‬‬
‫!‪Hello World‬‬
‫!‪Hello World‬‬
‫!‪Hello World‬‬
‫برنامه باال ‪ 10‬بار پیغام !‪ Hello World‬را چاپ میکند‪ .‬اگر از حلقه در مثال باال استفاده نمیکردیم مجبور بودیم تمام ‪ 10‬خط را تایپ کنیم‪ .‬اجازه دهید که‬
‫نگاهی به کدهای برنامه فوق بیندازیم‪ .‬ابتدا در خط ‪ 7‬یک متغیر تعریف و از آن به عنوان شمارنده حلقه استفاده شده است‪ .‬سپس به آن مقدار ‪ 1‬را اختصاص‬
‫میدهیم چون اگر مقدار نداشته باشد نمیتوان در شرط از آن استفاده کرد‪.‬‬
‫در خط ‪ 9‬حلقه ‪ While‬را وارد میکنیم‪ .‬در حلقه ‪ While‬ابتدا مقدار اولیه شمارنده با ‪ 10‬مقایسه میشود که آیا از ‪ 10‬کمتر است یا با آن برابر است‪ .‬نتیجه هر‬
‫بار مقایسه ورود به بدنه حلقه ‪ While‬و چاپ پیغام است‪ .‬همانطور که مشاهده میکنید بعد از هر بار مقایسه مقدار شمارنده یک واحد اضافه میشود (خط ‪.)12‬‬
‫حلقه تا زمانی تکرار میشود که مقدار شمارنده از ‪ 10‬کمتر باشد‪.‬‬
‫اگر مقدار شمارنده یک بماند و آن را افزایش ندهیم و یا مقدار شرط هرگز ‪ false‬نشود یک حلقه بینهایت به وجود میآید‪ .‬به این نکته توجه کنید که در شرط‬
‫باال به جای عالمت < از <= استفاده شده است‪ .‬اگر از عالمت < استفاده میکردیم کد ما ‪ 9‬بار تکرار میشد چون مقدار اولیه ‪ 1‬است و هنگامی که شرط به ‪10‬‬
‫برسد ‪ false‬میشود چون ‪ 10 < 10‬نیست‪ .‬اگر میخواهید یک حلقه بی نهایت ایجاد کنید که هیچگاه متوقف نشود باید یک شرط ایجاد کنید که همواره درست‬
‫(‪ )true‬باشد‪.‬‬

‫‪82‬‬
‫)‪while(true‬‬
‫{‬
‫‪//code to loop‬‬
‫}‬

‫این تکنیک در برخی موارد کارایی دارد و آن زمانی است که شما بخواهید با استفاده از دستورات ‪ break‬و ‪ return‬که در آینده توضیح خواهیم داد از حلقه‬
‫خارج شوید‪.‬‬

‫حلقه ‪do while‬‬

‫حلقه ‪ do while‬یکی دیگر از ساختارهای تکرار است‪ .‬این حلقه بسیار شبیه حلقه ‪ while‬است با این تفاوت که در این حلقه ابتدا کد اجرا می شودو سپس‬
‫شرط مورد بررسی قرار میگیرد‪ .‬ساختار حلقه ‪ do while‬به صورت زیر است ‪:‬‬

‫‪do‬‬
‫{‬
‫;‪code to repeat‬‬

‫;)‪} while (condition‬‬

‫همانطور که مشاهده میکنید شرط در آخر ساختار قرار دارد‪ .‬این بدین معنی است که کدهای داخل بدنه حداقل یکبار اجرا میشوند‪ .‬برخالف حلقه ‪ while‬که‬
‫اگر شرط نادرست باشد دستورات داخل بدنه اجرا نمیشوند‪ .‬برای اثبات این موضوع به کدهای زیر توجه کنید ‪:‬‬

‫;‪int number = 1‬‬


‫‪do‬‬
‫{‬
‫;)"!‪Console.WriteLine("Hello World‬‬
‫;)‪} while (number > 10‬‬

‫!‪Hello World‬‬
‫با اجرای کد باال‪ ،‬اول دستورات بلوک ‪ do‬اجرا میشوند و بعد مقدار ‪ number‬با عدد ‪ 10‬مقایسه میشود‪ .‬در نتیجه حتی اگر شرط نادرست باشد باز هم قسمت‬
‫‪ do‬حداقل یک بار اجرا میشوند‪.‬‬

‫;‪int number = 1‬‬


‫)‪while (number > 10‬‬
‫{‬
‫;)"!‪Console.WriteLine("Hello World‬‬
‫}‬

‫اما در کد باال چون اول مقدار ‪ number‬ابتدا مورد مقایسه قرار میگیرد‪ ،‬اگر شرط درست نباشد دیگر کدی اجرا نمیشود‪ .‬یکی از موارد برتری استفاده از حلقه‬
‫‪ do while‬نسبت به حلقه ‪ while‬زمانی است که شما بخواهید اطالعاتی از کاربر دریافت کنید‪ .‬در دو کد زیر‪ ،‬یک عملیات یکسان توسط دو حلقه ‪ while‬و‬
‫‪ do while‬پیاده سازی شده است ‪:‬‬
‫‪83‬‬
//while version

Console.WriteLine("Enter a number greater than 10: ");


number = Convert.ToInt32(Console.ReadLine());

while(number < 10)


{
Console.WriteLine("Enter a number greater than 10: ");
number = Convert.ToInt32(Console.ReadLine());
}
//do while version

do
{
Console.WriteLine("Enter a number greater than 10: ");
number = Convert.ToInt32(Console.ReadLine());
} while (number < 10);

.‫ استفاده شده است‬while ‫ نسبت به‬do while ‫مشاهده میکنید که از کدهای کمتری در بدنه‬

for ‫حلقه‬

‫ ساختار حلقه‬.‫ انجام میدهد و فقط دارای چند خصوصیت اضافی است‬while ‫ این حلقه عملی شبیه به حلقه‬.‫ است‬for ‫یکی دیگر از ساختارهای تکرار حلقه‬
: ‫ به صورت زیر است‬for

for(initialization; condition; operation)


{
code to repeat;
}

.‫ قابل دسترسی است‬for ‫ شمارنده فقط در داخل حلقه‬.‫) اولین مقداری است که به شمارنده حلقه میدهیم‬initialization( ‫مقدار دهی اولیه‬
.‫) در اینجا مقدار شمارنده را با یک مقدار دیگر مقایسه میکند و تعیین میکند که حلقه ادامه یابد یا نه‬condition( ‫شرط‬
.‫میدهد‬ ‫افزایش‬ ‫یا‬ ‫کاهش‬ ‫را‬ ‫متغیر‬ ‫اولیه‬ ‫مقدار‬ ‫که‬ )operation( ‫عملگر‬
:‫ آمده است‬for ‫در زیر یک مثال از حلقه‬

using System;

public class Program


{
public static void Main()
{
for(int i = 1; i <= 10; i++)
{
Console.WriteLine("Number " + i);
}
}
}

Number 1

84
‫‪Number 2‬‬
‫‪Number 3‬‬
‫‪Number 4‬‬
‫‪Number 5‬‬
‫‪Number 6‬‬
‫‪Number 7‬‬
‫‪Number 8‬‬
‫‪Number 9‬‬
‫‪Number 10‬‬
‫برنامه باال اعداد ‪ 1‬تا ‪ 10‬را با استفاده از حلقه ‪ for‬میشمارد‪ .‬ابتدا یک متغیر به عنوان شمارنده تعریف میکنیم و آن را با مقدار ‪ 1‬مقدار دهی اولیه میکنیم‪ .‬سپس‬
‫با استفاده از شرط آن را با مقدار ‪ 10‬مقایسه میکنیم که آیا کمتر است یا مساوی؟ توجه کنید که قسمت سوم حلقه )‪ (i++‬فوراً اجرا نمیشود‪ .‬کد اجرا میشود و‬
‫ابتدا رشته ‪ Number‬و سپس مقدار جاری ‪ i‬یعنی ‪ 1‬را چاپ میکند‪ .‬آنگاه یک واحد به مقدار ‪ i‬اضافه شده و مقدار ‪ i‬برابر ‪ 2‬میشود و بار دیگر ‪ i‬با عدد ‪10‬‬
‫مقایسه میشود و این حلقه تا زمانی که مقدار شرط ‪ true‬شود ادامه مییابد‪ .‬حال اگر بخواهید معکوس برنامه باال را پیاده سازی کنید یعنی اعداد از بزرگ به‬
‫کوچک چاپ شوند باید به صورت زیر عمل کنید ‪:‬‬

‫)‪for (int i = 10; i > 0; i--‬‬


‫{‬
‫‪//code omitted‬‬
‫}‬

‫کد باال اعداد را از ‪ 10‬به ‪ 1‬چاپ میکند (از بزرگ به کوچک)‪ .‬مقدار اولیه شمارنده را ‪ 10‬میدهیم و با استفاده از عملگر کاهش (–) برنامهای که شمارش معکوس‬
‫را انجام میدهد ایجاد میکنیم‪ .‬میتوان قسمت شرط و عملگر را به صورتهای دیگر نیز تغییر داد‪ .‬به عنوان مثال میتوان از عملگرهای منطقی در قسمت شرط‬
‫و از عملگرهای تخصیصی در قسمت عملگر افزایش یا کاهش استفاده کرد‪ .‬همچنین میتوانید از چندین متغیر در ساختار حلقه ‪ for‬استفاده کنید‪.‬‬

‫)‪for (int i = 1, y = 20; i < 10 && y >= 2; i++, y -= 2‬‬


‫{‬
‫‪//some code here‬‬
‫}‬

‫به این نکته توجه کنید که اگر از چندین متغیر شمارنده یا عملگر در حلقه ‪ for‬استفاده میکنید باید آنها را با استفاده از کاما از هم جدا کنید‪.‬‬

‫حلقه های تو در تو (‪)Nested Loops‬‬

‫سی شارپ به شما اجازه میدهد که از حلقه ها به صورت تو در تو استفاده کنید‪ .‬اگر یک حلقه در داخل حلقه دیگر قرار بگیرد‪ ،‬به آن حلقه تو در تو گفته میشود‪.‬‬
‫در این نوع حلقهها‪ ،‬به ازای اجرای یک بار حلقه بیرونی‪ ،‬حلقه داخلی به طور کامل اجرا میشود‪ .‬در زیر نحوه ایجاد حلقه تو در تو آمده است ‪:‬‬

‫)‪for (init; condition; increment‬‬


‫{‬
‫)‪for (init; condition; increment‬‬
‫{‬
‫;)‪//statement(s‬‬
‫}‬
‫;)‪//statement(s‬‬
‫}‬

‫)‪while(condition‬‬
‫{‬
‫‪85‬‬
‫)‪while(condition‬‬
‫{‬
‫;)‪//statement(s‬‬
‫}‬
‫;)‪//statement(s‬‬
‫}‬

‫‪do‬‬
‫{‬
‫;)‪//statement(s‬‬
‫‪do‬‬
‫{‬
‫;)‪//statement(s‬‬
‫}‬
‫;)‪while(condition‬‬

‫}‬
‫;)‪while(condition‬‬

‫نکتهای که در مورد حلقههای تو در تو وجود دارد این است که‪ ،‬میتوان از یک نوع حلقه در داخل نوع دیگر استفاده کرد‪ .‬مثالً میتوان از حلقه ‪ for‬در داخل حلقه‬
‫‪ while‬استفاده نمود‪ .‬در مثال زیر نحوه استفاده از این حلقهها ذکر شده است‪ .‬فرض کنید که میخواهید یک مستطیل با ‪ 3‬سطر و ‪ 5‬ستون ایجاد کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: namespace NestedLoopsDemo‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫‪class Program‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫)‪static void Main(string[] args‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫)‪for (int i = 1; i <= 4; i++‬‬
‫‪10:‬‬ ‫{‬
‫‪11:‬‬ ‫)‪for (int j = 1; j <= 5; j++‬‬
‫‪12:‬‬ ‫{‬
‫‪13:‬‬ ‫;)" * "(‪Console.Write‬‬
‫‪14:‬‬ ‫}‬
‫‪15:‬‬ ‫;)"‪Console.Write("\n‬‬
‫‪16:‬‬ ‫}‬
‫‪17:‬‬ ‫}‬
‫‪18:‬‬ ‫}‬
‫} ‪19:‬‬

‫*‬ ‫*‬ ‫*‬ ‫*‬ ‫*‬


‫*‬ ‫*‬ ‫*‬ ‫*‬ ‫*‬
‫*‬ ‫*‬ ‫*‬ ‫*‬ ‫*‬
‫*‬ ‫*‬ ‫*‬ ‫*‬ ‫*‬
‫در کد باال به ازای یک بار اجرای حلقه ‪ for‬اول (خط ‪ ،)9‬حلقه ‪ for‬دوم (‪ )11-14‬به طور کامل اجرا میشود‪ .‬یعنی وقتی مقدار ‪ i‬برابر عدد ‪ 1‬میشود‪،‬‬
‫عالمت * توسط حلقه دوم ‪ 5‬بار چاپ میشود‪ ،‬وقتی ‪ i‬برابر ‪ 2‬میشود‪ ،‬دوباره عالمت * پنج بار چاپ میشود و … ‪ .‬در کل منظور از دو حلقه ‪ for‬این است‬
‫که در ‪ 4‬سطر عالمت * در ‪ 5‬ستون چاپ شود یا ‪ 4‬سطر ایجاد شود و در هر سطر ‪ 5‬بار عالمت * چاپ شود‪ .‬خط ‪ 15‬هم برای ایجاد خط جدید است‪.‬‬

‫‪86‬‬
‫ البته به جای این خط میتوان‬.‫ یک خط جدید ایجاد میشود و عالمتهای * در خطوط جدید چاپ میشوند‬،‫یعنی وقتی حلقه داخلی به طور کامل اجرا شد‬
.‫ را هم نوشت‬Console.WriteLine();

continue ‫ و‬break ‫خارج شدن از حلقه با استفاده از‬

‫ حلقه را‬break ‫ سؤال اینجاست که چطور این کار را انجام دهید؟ با استفاده از کلمه کلیدی‬.‫گاهی اوقات با وجود درست بودن شرط می خواهیم حلقه متوقف شود‬
break ‫ و‬continue ‫ برنامه زیر نحوه استفاده از‬.‫ می توان بخشی از حلقه را رد کرد و به مرحله بعد رفت‬continue ‫متوقف کرده و با استفاده از کلمه کلیدی‬
: ‫را نشان میدهد‬

1: using System;
2:
3: public class Program
4: {
5: public static void Main()
6: {
7: Console.WriteLine("Demonstrating the use of break.n");
8:
9: for (int x = 1; x < 10; x++)
10: {
11: if (x == 5)
12: break;
13:
14: Console.WriteLine("Number " + x);
15: }
16:
17: Console.WriteLine("nDemonstrating the use of continue.n");
18:
19: for (int x = 1; x < 10; x++)
20: {
21: if (x == 5)
22: continue;
23:
24: Console.WriteLine("Number " + x);
25: }
26: }
27: }

Demonstrating the use of break.

Number 1
Number 2
Number 3
Number 4

Demonstrating the use of continue.

Number 1
Number 2
Number 3

87
‫‪Number 4‬‬
‫‪Number 6‬‬
‫‪Number 7‬‬
‫‪Number 8‬‬
‫‪Number 9‬‬
‫در این برنامه از حلقه ‪ for‬برای نشان دادن کاربرد دو کلمه کلیدی فوق استفاده شده است اگر به جای ‪ for‬از حلقههای ‪ while‬و ‪ do…while‬استفاده‬
‫میشد نتیجه یکسانی به دست میآمد‪ .‬همانطور که در شرط برنامه (خط ‪ )11‬آمده است‪ ،‬وقتی که مقدار ‪ x‬به عدد ‪ 5‬برسد‪ ،‬سپس دستور ‪ break‬اجرا (خط ‪ )12‬و‬
‫حلقه بالفاصله متوقف میشود‪ ،‬حتی اگر شرط ‪ x < 10‬برقرار باشد‪ .‬از طرف دیگر در خط ‪ 22‬حلقه ‪ for‬فقط برای یک تکرار خاص متوقف شده و سپس ادامه‬
‫مییابد‪( .‬وقتی مقدار ‪ x‬برابر ‪ 5‬شود حلقه از ‪ 5‬رد شده و مقدار ‪ 5‬را چاپ نمیکند و بقیه مقادیر چاپ میشوند‪.‬‬

‫آرایه ها‬

‫آرایه نوعی متغیر است که لیستی از آدرسهای مجموعهای از دادههای هم نوع را در خود ذخیره میکند‪ .‬تعریف چندین متغیر از یک نوع برای هدفی یکسان بسیار‬
‫خسته کننده است‪ .‬مثالً اگر بخواهید صد متغیر از نوع اعداد صحیح تعریف کرده و از آنها استفاده کنید‪ .‬مطمئناً تعریف این همه متغیر بسیار کسالت آور و خسته‬
‫کننده است‪ .‬اما با استفاده از آرایه میتوان همه آنها را در یک خط تعریف کرد‪ .‬در زیر راهی ساده برای تعریف یک آرایه نشان داده شده است ‪:‬‬

‫;]‪datatype[] arrayName = new datatype[length‬‬

‫‪ Datatype‬نوع دادههایی را نشان میدهد که آرایه در خود ذخیره میکند‪ .‬کروشه که بعد از نوع داده قرار میگیرد و نشان دهنده استفاده از آرایه‬
‫است‪ arrayName.‬که نام آرایه را نشان می دهد‪ .‬هنگام نامگذاری آرایه بهتر است که نام آرایه نشان دهنده نوع آرایه باشد‪ .‬به عنوان مثال برای نامگذاری‬
‫آرایهای که اعداد را در خود ذخیره میکند از کلمه ‪ number‬استفاده کنید‪ .‬طول آرایه که به کامپایلر میگوید شما قصد دارید چه تعداد داده یا مقدار را در آرایه‬
‫ذخیره کنید‪ .‬از کلمه کلیدی ‪ new‬هم برای اختصاص فضای حافظه به اندازه طول آرایه استفاده میشود‪ .‬برای تعریف یک آرایه که ‪ 5‬مقدار از نوع اعداد صحیح‬
‫در خود ذخیره میکند باید به صورت زیر عمل کنیم ‪:‬‬

‫;]‪int[] numbers = new int[5‬‬

‫در این مثال ‪ 5‬آدرس از فضای حافظه کامپیوتر شما برای ذخیره ‪ 5‬مقدار رزرو می شود‪ .‬حال چطور مقادیرمان را در هر یک از این آدرسها ذخیره کنیم؟ برای‬
‫دسترسی و اصالح مقادیر آرایه از اندیس یا مکان آنها استفاده میشود‪.‬‬

‫;‪numbers[0] = 1‬‬
‫;‪numbers[1] = 2‬‬
‫;‪numbers[2] = 3‬‬
‫;‪numbers[3] = 4‬‬
‫;‪numbers[4] = 5‬‬

‫اندیس یک آرایه از صفر شروع شده و به یک واحد کمتر از طول آرایه ختم میشود‪ .‬به عنوان مثال شما یک آرایه ‪ 5‬عضوی دارید‪ ،‬اندیس آرایه از ‪ 0‬تا ‪ 4‬میباشد‬
‫چون طول آرایه ‪ 5‬است پس ‪ 5-1‬برابر است با ‪ .4‬این بدان معناست که اندیس ‪ 0‬نشان دهنده اولین عضو آرایه است و اندیس ‪ 1‬نشان دهنده دومین عضو و الی‬
‫‪:‬‬ ‫کنید‬ ‫توجه‬ ‫زیر‬ ‫شکل‬ ‫به‬ ‫باال‬ ‫مثال‬ ‫بهتر‬ ‫درک‬ ‫برای‬ ‫آخر‪.‬‬

‫به هر یک از اجزاء آرایه و اندیسهای داخل کروشه توجه کنید‪ .‬کسانی که تازه شروع به برنامه نویسی کردهاند معموالً در گذاشتن اندیس دچار اشتباه میشوند و‬
‫‪88‬‬
‫مثالً ممکن است در مثال باال اندیسها را از ‪ 1‬شروع کنند‪ .‬اگر بخواهید به یکی از اجزائ آرایه با استفاده از اندیسی دسترسی پیدا کنید که در محدوده اندیسهای‬
‫آرایه شما نباشد با پیغام خطای ‪ IndexOutOfRangeException‬مواجه میشوید و بدین معنی است که شما آدرسی را میخواهید که وجود ندارد‪ .‬یکی‬
‫دیگر از راههای تعریف سریع و مقدار دهی یک آرایه به صورت زیر است ‪:‬‬

‫;} ‪datatype[] arrayName = new datatype[length] { val1, val2, ... valN‬‬

‫در این روش شما میتوانید فوراً بعد از تعریف اندازه آرایه مقادیر را در داخل آکوالد قرار دهید‪ .‬به یاد داشته باشید که هر کدام از مقادیر را با استفاده از کاما از هم‬
‫جدا کنید‪ .‬همچنین تعداد مقادیر داخل آکوالد باید با اندازه آرایه تعریف شده برابر باشد‪ .‬به مثال زیر توجه کنید ‪:‬‬

‫;} ‪int[] numbers = new int[5] { 1, 2, 3, 4, 5‬‬

‫این مثال با مثال قبل هیچ تفاوتی ندارد و تعداد خطهای کدنویسی را کاهش میدهد‪ .‬شما میتوانید با استفاده از اندیس به مقدار هر یک از اجزاء آرایه دسترسی‬
‫یابید و آنها را به دلخواه تغییر دهید‪ .‬تعداد اجزاء آرایه در مثال باال ‪ 5‬است و ما ‪ 5‬مقدار را در آن قرار میدهیم‪ .‬اگر تعداد مقادیری که در آرایه قرار میدهیم کمتر یا‬
‫بیشتر از طول آرایه باشد با خطا مواجه میشویم‪ .‬یکی دیگر از راههای تعریف آرایه در زیر آمده است‪ .‬شما میتوانید هر تعداد عنصر را که خواستید در آرایه قرار‬
‫دهید بدون اینکه اندازه آرایه را مشخص کنید‪ .‬به عنوان مثال ‪:‬‬

‫;} ‪int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10‬‬

‫در این مثال ما ‪ 10‬مقدار را به آرایه اختصاص دادهایم‪ .‬نکته اینجاست که طول آرایه را تعریف نکردهایم‪ .‬در این حالت کامپایلر بعد از شمردن تعداد مقادیر داخل‬
‫آکوالد طول آرایه را تشخیص میدهد‪ .‬به یاد داشته باشید که اگر برای آرایه طولی در نظر نگیرید باید برای آن مقدار تعریف کنید در عیر این صورت با خطا مواجه‬
‫میشوید ‪:‬‬

‫‪int[] numbers = new int[]; //not allowed‬‬

‫یک راه بسیار سادهتر برای تعریف آرایه به صورت زیر است ‪:‬‬

‫;} ‪int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10‬‬

‫به سادگی و بدون احتیاج به کلمه کلیدی ‪ new‬می توان مقادیر را در داخل آکوالد قرار داد‪ .‬کامپایلر به صورت اتوماتیک با شمارش مقادیر طول آرایه را تشخیص‬
‫میدهد‪.‬‬

‫دستیابی به مقادیر آرایه با استفاده از حلقه ‪for‬‬

‫در زیر مثالی در مورد استفاده از آرایهها آمده است‪ .‬در این برنامه ‪ 5‬مقدار از کاربر گرفته شده و میانگین آنها حساب میشود‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;]‪int[] numbers = new int[5‬‬
‫‪8:‬‬ ‫;‪int total = 0‬‬
‫‪9:‬‬ ‫;‪double average‬‬
‫‪10:‬‬
‫‪11:‬‬ ‫)‪for (int i = 0; i < numbers.Length; i++‬‬

‫‪89‬‬
‫‪12:‬‬ ‫{‬
‫‪13:‬‬ ‫;)" ‪Console.Write("Enter a number:‬‬
‫‪14:‬‬ ‫;))(‪numbers[i] = Convert.ToInt32(Console.ReadLine‬‬
‫‪15:‬‬ ‫}‬
‫‪16:‬‬
‫‪17:‬‬ ‫)‪for (int i = 0; i < numbers.Length; i++‬‬
‫‪18:‬‬ ‫{‬
‫‪19:‬‬ ‫;]‪total += numbers[i‬‬
‫‪20:‬‬ ‫}‬
‫‪21:‬‬
‫‪22:‬‬ ‫;‪average = total / (double)numbers.Length‬‬
‫‪23:‬‬
‫‪24:‬‬ ‫;)‪Console.WriteLine("Average = {0}", average‬‬
‫‪25:‬‬ ‫}‬
‫} ‪26:‬‬

‫‪Enter a number: 90‬‬


‫‪Enter a number: 85‬‬
‫‪Enter a number: 80‬‬
‫‪Enter a number: 87‬‬
‫‪Enter a number: 92‬‬
‫‪Average = 86‬‬
‫در خط ‪ 7‬یک آرایه تعریف شده است که میتواند ‪ 5‬عدد صحیح را در خود ذخیره کند‪ .‬خطوط ‪ 8‬و ‪ 9‬متغیرهایی تعریف شدهاند که از آنها برای محاسبه میانگین‬
‫استفاده میشود‪ .‬توجه کنید که مقدار اولیه ‪ total‬صفر است تا از بروز خطا هنگام اضافه شدن مقدار به آن جلوگیری شود‪ .‬در خطوط ‪ 11‬تا ‪ 15‬حلقه ‪ for‬برای‬
‫تکرار و گرفتن ورودی از کاربر تعریف شده است‪ .‬از خاصیت طول (‪ )length‬ارائه برای تشخیص تعداد اجزای آرایه استفاده میشود‪ .‬اگر چه میتوانستیم به‬
‫سادگی در حلقه ‪ for‬مقدار ‪ 5‬را برای شرط قرار دهیم ولی استفاده از خاصیت طول آرایه کار راحتتری است و میتوانیم طول آرایه را تغییر دهیم و شرط حلقه‬
‫‪ for‬با تغییر جدید هماهنگ میشود‪ .‬در خط ‪ 14‬ورودی دریافت شده از کاربر به نوع ‪ int‬تبدیل و در آرایه ذخیره میشود‪ .‬اندیس استفاده شده در ‪number‬‬
‫(خط ‪ )14‬مقدار ‪ i‬جاری در حلقه است‪ .‬برای مثال در ابتدای حلقه مقدار ‪ i‬صفر است بنابراین وقتی در خط ‪ 14‬اولین داده از کاربر گرفته میشود اندیس آن برابر‬
‫صفر میشود‪ .‬در تکرار بعدی ‪ i‬یک واحد اضافه میشود و در نتیجه در خط ‪ 14‬و بعد از ورود دومین داده توسط کاربر اندیس آن برابر یک میشود‪ .‬این حالت تا‬
‫زمانی که شرط در حلقه ‪ for‬برقرار است ادامه مییابد‪ .‬در خطوط ‪ 17-20‬از حلقه ‪ for‬دیگر برای دسترسی به مقدار هر یک از دادههای آرایه استفاده شده است‪.‬‬
‫در این حلقه نیز مانند حلقه قبل از مقدار متغیر شمارنده به عنوان اندیس استفاده میکنیم‪.‬‬
‫هر یک از اجزای عددی آرایه به متغیر ‪ total‬اضافه میشوند‪ .‬بعد از پایان حلقه میتوانیم میانگین اعداد را حساب کنیم (خط ‪ .)22‬مقدار ‪ total‬را بر تعداد اجزای‬
‫آرایه (تعداد عددها) تقسیم میکنیم‪ .‬برای دسترسی به تعداد اجزای آرایه میتوان از خاصیت ‪ length‬آرایه استفاده کرد‪ .‬توجه کنید که در اینجا ما مقدار خاصیت‬
‫‪ length‬را به نوع ‪ double‬تبدیل کردهایم بنابراین نتیجه عبارت یک مقدار از نوع ‪ double‬خواهد شد و دارای بخش کسری میباشد‪ .‬حال اگر عملوندهای‬
‫تقسیم را به نوع ‪ double‬تبدی ل نکنیم نتیجه تقسیم یک عدد از نوع صحیح خواهد شد و دارای بخش کسری نیست‪ .‬خط ‪ 24‬مقدار میانگین را در صفحه‬
‫نمایش چاپ میکند‪ .‬طول آرایه بعد از مقدار دهی نمیتواند تغیر کند‪ .‬به عنوان مثال اگر یک آرایه را که شامل ‪ 5‬جز است مقدار دهی کنید دیگر نمیتوانید آن را‬
‫مثالً به ‪ 10‬جز تغییر اندازه دهید‪ .‬البته تعداد خاصی از کالسها مانند آرایهها عمل میکنند و توانایی تغییر تعداد اجزای تشکیل دهنده خود را دارند‪ .‬آرایهها در برخی‬
‫شرایط بسیار پر کاربرد هستند و تسلط شما بر این مفهوم و اینکه چطور از آنها استفاده کنید بسیار مهم است‪.‬‬

‫حلقه ‪foreach‬‬

‫‪90‬‬
‫حلقه ‪ foreach‬یکی دیگر از ساختارهای تکرار در سی شارپ میباشد که مخصوصاً برای آرایهها‪ ،‬لیستها و مجموعهها طراحی شده است‪ .‬حلقه ‪ foreach‬با‬
‫هر بار گردش در بین اجزاء‪ ،‬مقادیر هر یک از آنها را در داخل یک متغیر موقتی قرار میدهد و شما میتوانید بواسطه این متغیر به مقادیر دسترسی پیدا کنید‪ .‬در‬
‫زیر نحوه استفاده از حلقه ‪ foreach‬آمده است ‪:‬‬

‫)‪foreach (datatype temporaryVar in array‬‬


‫{‬
‫;‪code to execute‬‬
‫}‬

‫‪ temporaryVar‬متغیری است که مقادیر اجزای آرایه را در خود نگهداری میکند‪ temporaryVar.‬باید دارای نوع باشد تا بتواند مقادیر آرایه را در خود‬
‫ذخیره کند‪ .‬به عنوان مثال آرایه شما دارای اعدادی از نوع صحیح باشد باید نوع متغیر موقتی از نوع اعداد صحیح باشد یا هر نوع دیگری که بتواند اعداد صحیح را‬
‫در خود ذخیره کند مانند ‪ double‬یا ‪ .long‬سپس کلمه کلیدی ‪ in‬و بعد از آن نام آرایه را مینویسیم‪ .‬در زیر نحوه استفاده از حلقه ‪ foreach‬آمده است ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;} ‪int[] numbers = { 1, 2, 3, 4, 5‬‬
‫‪8:‬‬
‫‪9:‬‬ ‫)‪foreach (int n in numbers‬‬
‫‪10:‬‬ ‫{‬
‫‪11:‬‬ ‫;)‪Console.WriteLine("Number {0}", n‬‬
‫‪12:‬‬ ‫}‬
‫‪13:‬‬ ‫}‬
‫} ‪14:‬‬

‫‪Number 1‬‬
‫‪Number 2‬‬
‫‪Number 3‬‬
‫‪Number 4‬‬
‫‪Number 5‬‬
‫در برنامه آرایهای با ‪ 5‬جزء تعریف شده و مقادیر ‪ 1‬تا ‪ 5‬در آنها قرار داده شده است (خط ‪ .)7‬در خط ‪ 9‬حلقه ‪ foreach‬شروع میشود‪ .‬ما یک متغیر موقتی تعریف‬
‫کردهایم که اعداد آرایه را در خود ذخیره میکند‪ .‬در هر بار تکرار از حلقه ‪ foreach‬متغیر موقتی ‪ ، n‬مقادیر عددی را از آرایه استخراج میکند‪ .‬حلقه ‪foreach‬‬
‫مقادیر اولین تا آخرین جزء آرایه را در اختیار ما قرار میدهد‪.‬‬
‫حلقه ‪ foreach‬برای دریافت هر یک از مقادیر آرایه کاربرد دارد‪ .‬بعد از گرفتن مقدار یکی از اجزای آرایه‪ ،‬مقدار متغیر موقتی را چاپ میکنیم‪ .‬حلقه ‪foreach‬‬
‫یک ضعف دارد و آن اینست که این حلقه ما را قادر میسازد که به دادهها دسترسی یابیم و یا آنها را بخوانیم ولی اجازه اصالح اجزاء آرایه را نمیدهد‪ .‬برای درک‬
‫این مطلب در مثال زیر سعی شده است که مقدار هر یک از اجزا آرایه افزایش یابد ‪:‬‬

‫;} ‪int[] numbers = { 1, 2, 3‬‬

‫)‪foreach(int number in numbers‬‬


‫{‬
‫;‪number++‬‬
‫}‬

‫اگر برنامه را اجرا کنید با خطا مواجه میشوید‪ .‬برای اصالح هر یک از اجزا آرایه میتوان از حلقه ‪ for‬استفاده کرد‪.‬‬
‫‪91‬‬
‫;} ‪int[] numbers = { 1, 2, 3‬‬

‫)‪for (int i = 0; i < number.Length; i++‬‬


‫{‬
‫;‪numbers[i]++‬‬
‫}‬

‫این حلقه یه ضعف دیگر نیز دارد و آن این است که ما نمیتوانیم با استفاده از حلقه ‪ foreach‬به اندیس عناصر آرایه دست یابیم‪ ،‬مثالً کد زیر که با حلقه ‪for‬‬
‫نوشته شده است را نمیتوانیم با حلقه ‪ foreach‬پیاده سازی کنیم‪:‬‬

‫;}‪int[] number = {1, 2, 3, 4‬‬

‫)‪for (int i = 0; i < number.Length; i++‬‬


‫{‬
‫;)]‪Console.WriteLine(number[i‬‬
‫}‬

‫البته این ضعف نیز به نوعی ناشی از غیر قابل ویرایش بودن عناصر آرایه در حلقه ‪ foreach‬است‪.‬‬

‫آرایه های چند بعدی‬

‫آرایههای چند بعدی آرایههایی هستند که برای دسترسی به هر یک از عناصر آنها باید از چندین اندیس استفاده کنیم‪ .‬یک آرایه چند بعدی را میتوان مانند یک‬
‫جدول با تعدای ستون و ردیف تصور کنید‪ .‬با افزایش اندیسها اندازه ابعاد آرایه نیز افزایش مییابد و آرایههای چند بعدی با بیش از دو اندیس به وجود میآیند‪.‬‬
‫نحوه ایجاد یک آرایه با دو بعد به صورت زیر است ‪:‬‬

‫;]‪datatype[,] arrayName = new datatype[lengthX, lengthY‬‬

‫و یک آرایه سه بعدی به صورت زیر ایجاد میشود ‪:‬‬

‫;]‪datatype[, ,] arrayName = new datatype[lengthX, lengthY, lengthZ‬‬

‫می توان یک آرایه با تعداد زیادی بعد ایجاد کرد به شرطی که هر بعد دارای طول مشخصی باشد‪ .‬به دلیل اینکه آرایههای سه بعدی یا آرایههای با بیشتر از دو بعد‬
‫بسیار کمتر مورد استفاده قرار میگیرند اجازه بدهید که در این درس بر روی آرایههای دو بعدی تمرکز کنیم‪ .‬در تعریف این نوع آرایه ابتدا نوع آرایه یعنی اینکه‬
‫آرایه چه نوعی از انواع داده را در خود ذخیره میکند را مشخص میکنیم‪ .‬سپس یک جفت کروشه و در داخل کروشهها یک کاما قرار میدهیم‪ .‬به تعداد کاماهایی‬
‫که در داخل کروشه میگذارید توجه کنید‪ .‬اگر آرایه ما دو بعدی است باید ‪ 1‬کاما و اگر سه بعدی است باید ‪ 2‬کاما قرار دهیم‪ .‬سپس یک نام برای آرایه انتخاب‬
‫کرده و بعد تعریف آنرا با گذاشتن کلمه ‪ ، new‬نوع داده و طول آن کامل میکنیم‪ .‬در یک آرایه دو بعدی برای دسترسی به هر یک از عناصر به دو مقدار نیاز‬
‫داریم یکی مقدار ‪ X‬و دیگری مقدار ‪ Y‬که مقدار ‪ x‬نشان دهنده ردیف و مقدار ‪ Y‬نشان دهنده ستون آرایه است البته اگر ما آرایه دو بعدی را به صورت جدول در‬
‫نظر بگیریم‪ .‬یک آرایه سه بعدی را میتوان به صورت یک مکعب تصور کرد که دارای سه بعد است و ‪ x‬طول‪ Y ،‬عرض و ‪ z‬ارتفاع آن است‪ .‬یک مثال از آرایه‬
‫دو بعدی در زیر آمده است ‪:‬‬

‫;]‪int[,] numbers = new int[3, 5‬‬

‫کد باال به کامپایلر میگوید که فضای کافی به عناصر آرایه اختصاص بده (در این مثال ‪ 15‬خانه)‪ .‬در شکل زیر مکان هر عنصر در یک آرایه دو بعدی نشان داده‬
‫شده است‪.‬‬

‫‪92‬‬
‫مقدار ‪ 3‬را به ‪ x‬اختصاص میدهیم چون ‪ 3‬سطر و مقدار ‪ 5‬را به ‪ Y‬چون ‪ 5‬ستون داریم اختصاص میدهیم‪ .‬چطور یک آرایه چند بعدی را مقدار دهی کنیم؟ چند‬
‫راه برای مقدار دهی به آرایهها وجود دارد‪.‬‬

‫‪datatype[,] arrayName = new datatype[x, y] { { r0c0, r0c1, ... r0cX },‬‬


‫‪{ r1c0, r1c1, ... r1cX },‬‬
‫‪.‬‬
‫‪.‬‬
‫‪.‬‬
‫;} } ‪{ rYc0, rYc1, ... rYcX‬‬

‫برای راحتی کار میتوان از نوشتن قسمت ]‪ new dataype[,‬صرف نظر کرد‪.‬‬

‫‪datatype[,] arrayName = { { r0c0, r0c1, ... r0cX },‬‬


‫‪{ r1c0, r1c1, ... r1cX },‬‬
‫‪.‬‬
‫‪.‬‬
‫‪.‬‬
‫;} } ‪{ rYc0, rYc1, ... rYcX‬‬

‫به عنوان مثال ‪:‬‬

‫‪int[,] numbers = { { 1, 2, 3, 4, 5 },‬‬


‫‪{ 6, 7, 8, 9, 10 },‬‬
‫;} } ‪{ 11, 12, 13, 14, 15‬‬

‫و یا میتوان مقدار دهی به عناصر را به صورت دستی انجام داد مانند ‪:‬‬

‫;‪array[0, 0] = value‬‬
‫;‪array[0, 1] = value‬‬
‫;‪array[0, 2] = value‬‬
‫;‪array[1, 0] = value‬‬
‫;‪array[1, 1] = value‬‬
‫;‪array[1, 2] = value‬‬
‫;‪array[2, 0] = value‬‬
‫;‪array[2, 1] = value‬‬
‫;‪array[2, 2] = value‬‬

‫‪93‬‬
‫همانطور که مشاهده میکنید برای دسترسی به هر یک از عناصر در یک آرایه دو بعدی به سادگی میتوان از اندیسهای ‪ X‬و ‪ Y‬و یک جفت کروشه مانند مثال‬
‫استفاده کرد‪.‬‬

‫گردش در میان عناصر آرایههای چند بعدی‬

‫گردش در میان عناصر آرایههای چند بعدی نیاز به کمی دقت دارد‪ .‬یکی از راههای آسان استفاده از حلقه ‪ foreach‬و یا حلقه ‪ for‬تو در تو است‪ .‬اجازه دهید‬
‫ابتدا از حلقه ‪ foreach‬استفاده کنیم‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫‪int[,] numbers = { { 1, 2, 3, 4, 5 },‬‬
‫‪8:‬‬ ‫‪{ 6, 7, 8, 9, 10 },‬‬
‫‪9:‬‬ ‫} ‪{ 11, 12, 13, 14, 15‬‬
‫‪10:‬‬ ‫;}‬
‫‪11:‬‬
‫‪12:‬‬ ‫)‪foreach (int number in numbers‬‬
‫‪13:‬‬ ‫{‬
‫‪14:‬‬ ‫;)" " ‪Console.Write(number +‬‬
‫‪15:‬‬ ‫}‬
‫‪16:‬‬ ‫}‬
‫} ‪17:‬‬

‫‪1 2 3 4 5 6 7 8 9 10 11 12 13 14 15‬‬
‫مشاهده کردید که گردش در میان مقادیر عناصر یک آرایه چند بعدی چقدر راحت است‪ .‬به وسیله حلقه ‪ foreach‬نمیتوانیم انتهای ردیفها را مشخص کنیم‪.‬‬
‫برنامه زیر نشان میدهد که چطور از حلقه ‪ for‬برای خواندن همه مقادیر آرایه و تعیین انتهای ردیفها استفاده کنید‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫‪int[,] numbers = { { 1, 2, 3, 4, 5 },‬‬
‫‪8:‬‬ ‫‪{ 6, 7, 8, 9, 10 },‬‬
‫‪9:‬‬ ‫} ‪{ 11, 12, 13, 14, 15‬‬
‫‪10:‬‬ ‫;}‬
‫‪11:‬‬
‫‪12:‬‬ ‫)‪for (int row = 0; row < numbers.GetLength(0); row++‬‬
‫‪13:‬‬ ‫{‬
‫‪14:‬‬ ‫)‪for (int col = 0; col < numbers.GetLength(1); col++‬‬
‫‪15:‬‬ ‫{‬
‫‪16:‬‬ ‫;)" " ‪Console.Write(numbers[row, col] +‬‬
‫‪17:‬‬ ‫}‬
‫‪18:‬‬
‫‪19:‬‬ ‫‪//Go to the next line‬‬

‫‪94‬‬
‫‪20:‬‬ ‫;)(‪Console.WriteLine‬‬
‫‪21:‬‬ ‫}‬
‫‪22:‬‬ ‫}‬
‫} ‪23:‬‬

‫‪1 2 3 4 5‬‬
‫‪6 7 8 9 10‬‬
‫‪11 12 13 14 15‬‬
‫همانطور که در مثال باال نشان داده شده است با استفاده از یک حلقه ‪ for‬نمیتوان به مقادیر دسترسی یافت بلکه به یک حلقه ‪ for‬تو در تو نیاز داریم‪ ،‬زیرا آرایه‬
‫دو بعدی به صورت یک جدول شامل سطر و ستون است‪ ،‬پس الزم است که از یک حلقه ‪ for‬برای گردش در میان سطرها و از حلقه ‪ for‬دیگر برای گردش در‬
‫کنیم‪.‬‬ ‫استفاده‬ ‫(آرایه)‬ ‫جدول‬ ‫این‬ ‫ستونهای‬ ‫میان‬
‫اولین حلقه ‪( for‬خط ‪ )12‬برای گردش در میان ردیفهای آرایه به کار میرود‪ .‬این حلقه تا زمانی ادامه مییابد که مقدار ردیف کمتر از طول اولین بعد باشد (زیرا‬
‫اندیس ابعاد آرایه از صفر شروع میشود‪ .‬در مثال باال مقدار اولین بعد برابر ‪ 3‬است)‪ .‬در این مثال از متد )(‪ GetLength‬کالس ‪ Array‬استفاده کردهایم‪ .‬این‬
‫متد طول آرایه را در یک بعد خاص نشان میدهد و دارای یک پارامتر است که همان بعد آرایه میباشد‪ .‬به عنوان مثال برای به دست آوردن طول اولین بعد آرایه‬
‫مقدار صفر را به این متد ارسال میکنیم چون اندیس ابعاد آرایه از صفر شروع میشود‪.‬‬
‫در داخل اولین حلقه ‪ for‬حلقه ‪ for‬دیگری تعریف شده است (خط ‪ .)14‬در این حلقه یک شمارنده برای شمارش تعداد ستونهای )‪ (col‬هر ردیف تعریف شده‬
‫است و در شرط داخل آن بار دیگر از متد )(‪ GetLength‬استفاده شده است‪ ،‬ولی این بار مقدار ‪ 1‬را به آن ارسال میکنیم تا طول بعد دوم آرایه را به دست‬
‫آوریم‪ .‬پس به عنوان مثال وقتی که مقدار ردیف )‪ (row‬صفر باشد‪ ،‬حلقه دوم از [‪ ]0 ,0‬تا [‪ ]4 ,0‬اجرا میشود‪ .‬سپس مقدار هر عنصر از آرایه را با استفاده از حلقه‬
‫نشان میدهیم‪ ،‬اگر مقدار ردیف)‪ (row‬برابر ‪ 0‬و مقدار ستون )‪ (col‬برابر ‪ 0‬باشد مقدار عنصری که در ستون ‪ 1‬و ردیف ‪ (numbers[0, 0]) 1‬قرار دارد‬
‫نشان داده خواهد شد که در مثال باال عدد ‪ 1‬است‪.‬‬
‫بعد از اینکه دومین حلقه تکرار به پایان رسید‪ ،‬فوراً دستورات بعد از آن اجرا خواهند شد‪ ،‬که در اینجا دستور )(‪ Console.WriteLine‬که به برنامه اطالع‬
‫میدهد که به خط بعد برود‪ .‬سپس حلقه با اضافه کردن یک واحد به مقدار ‪ row‬این فرایند را دوباره تکرار میکند‪ .‬سپس دومین حلقه ‪ for‬اجرا شده و مقادیر‬
‫دومین ردیف نمایش داده میشود‪ .‬این فرایند تا زمانی اجرا میشود که مقدار ‪ row‬کمتر از طول اولین بعد باشد‪ .‬حال بیایید آنچه را از قبل یاد گرفتهایم در یک‬
‫برنامه به کار بریم‪ .‬این برنامه نمره چهار درس مربوط به سه دانش آموز را از ما میگیرد و معدل سه دانش آموز را حساب میکند‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;]‪double[,] studentGrades = new double[3, 4‬‬
‫‪8:‬‬ ‫;‪double total‬‬
‫‪9:‬‬
‫‪10:‬‬ ‫)‪for (int student = 0; student < studentGrades.GetLength(0); student++‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫;‪total = 0‬‬
‫‪13:‬‬
‫‪14:‬‬ ‫;)‪Console.WriteLine("Enter grades for Student {0}", student + 1‬‬
‫‪15:‬‬
‫‪16:‬‬ ‫)‪for (int grade = 0; grade < studentGrades.GetLength(1); grade++‬‬
‫‪17:‬‬ ‫{‬
‫‪18:‬‬ ‫;)‪Console.Write("Enter Grade #{0}: ", grade + 1‬‬
‫‪19:‬‬ ‫;))(‪studentGrades[student, grade] = Convert.ToDouble(Console.ReadLine‬‬
‫‪20:‬‬ ‫;]‪total += studentGrades[student, grade‬‬
‫‪21:‬‬ ‫}‬

‫‪95‬‬
‫‪22:‬‬
‫‪23:‬‬ ‫‪Console.WriteLine("Average is {0:F2}",‬‬
‫‪24:‬‬ ‫;)))‪(total / studentGrades.GetLength(1‬‬
‫‪25:‬‬ ‫;)(‪Console.WriteLine‬‬
‫‪26:‬‬ ‫}‬
‫‪27:‬‬
‫‪28:‬‬ ‫}‬
‫} ‪29:‬‬

‫‪Enter grades for Student 1‬‬


‫‪Enter Grade #1: 92‬‬
‫‪Enter Grade #2: 87‬‬
‫‪Enter Grade #3: 89‬‬
‫‪Enter Grade #4: 95‬‬
‫‪Average is 90.75‬‬

‫‪Enter grades for Student 2‬‬


‫‪Enter Grade #1: 85‬‬
‫‪Enter Grade #2: 85‬‬
‫‪Enter Grade #3: 86‬‬
‫‪Enter Grade #4: 87‬‬
‫‪Average is 85.75‬‬

‫‪Enter grades for Student 3‬‬


‫‪Enter Grade #1: 90‬‬
‫‪Enter Grade #2: 90‬‬
‫‪Enter Grade #3: 90‬‬
‫‪Enter Grade #4: 90‬‬
‫‪Average is 90.00‬‬
‫در برنامه باال یک آرایه چند بعدی از نوع ‪ double‬تعریف شده است (خط ‪ .)7‬همچنین یک متغیر به نام ‪ total‬تعریف میکنیم که جمع نمرات وارد شده برای‬
‫دانش آموز در آن قرار میگیرد‪ .‬حال وارد حلقه ‪ for‬تو در تو میشویم (خط ‪ .)10‬در اولین حلقه ‪ for‬یک متغیر به نام ‪ student‬تعریف کردهایم که مقادیر اولین‬
‫بعد آرایه (که همان تعداد دانش آموزان است) در آن قرار میگیرد‪ .‬از متد )(‪ GetLength‬هم برای تشخیص تعداد دانش آموزان استفاده شده است‪ .‬وارد بدنه‬
‫حلقه ‪ for‬میشویم‪ .‬در خط ‪ 12‬مقدار متغیر ‪ total‬را برابر صفر قرار میدهیم‪ .‬سپس برنامه یک پیغام را نشان میدهد و از شما میخواهد که نمرات دانش آموز را‬
‫وارد کنید (‪ .)student + 1‬عدد ‪ 1‬را به ‪ student‬اضافه کردهایم تا به جای نمایش ‪ ،Student 0‬با ‪ Student 1‬شروع شود‪ ،‬تا طبیعیتر به نظر برسد‪.‬‬
‫سپس به دومین حلقه ‪ for‬در خط ‪ 16‬میرسیم‪ .‬وظیفه این حلقه گردش در میان دومین بعد که همان نمرات دانش آموز است میباشد‪ .‬برنامه چهار نمره مربوط‬
‫به دانش آموز را میگیرد‪ .‬هر وقت که برنامه یک نمره را از کاربر دریافت میکند‪ ،‬نمره به متغیر ‪ total‬اضافه میشود‪.‬‬
‫وقتی همه نمرهها وارد شدند‪ ،‬متغیر ‪ total‬هم جمع همه نمرات را نشان میدهد‪ .‬در خطوط ‪ 23-24‬معدل دانش آموز نشان داده میشود‪ .‬به فرمت‬
‫}‪ {0:F2‬توجه کنید‪ .‬این فرمت معدل را تا دو رقم اعشار نشان میدهد‪ .‬معدل از تقسیم کردن ‪( total‬جمع) بر تعداد نمرات به دست میآید‪ .‬از متد‬
‫)‪ GetLength(1‬هم برای به دست آوردن تعداد نمرات استفاده میشود‪.‬‬

‫آرایه دندانه دار‬

‫آرایه دندانه دار یا ‪ jagged array‬آرایهای چند بعدی است که دارای سطرهای با طول متغیر میباشد‪ .‬نمونه سادهای از آرایههای چند بعدی‪ ،‬آرایههای‬
‫مستطیلی است که تعداد ستونهای سطرهای آنها برابر است‪ .‬اما آرایههای دندانه دار دارای سطرهایی با طول متفاوت میباشند‪ .‬بنابر این آرایههای دندانه دار را‬
‫میتوان آرایهای از آرایهها فرض کرد‪ .‬دستور نوشتن این نوع آرایهها به صورت زیر است ‪:‬‬

‫‪96‬‬
‫;‪datatype[][] arrayName‬‬

‫ابتدا ‪ datatype‬که نوع آرایه است و سپس چهار کروشه باز و بسته و بعد از آن نام آرایه را مینویسیم‪ .‬مقداردهی به این آرایهها کمی گیج کننده است‪ .‬به مثال‬
‫زیر توجه کنید ‪:‬‬

‫;][]‪int[][] myArrays = new int[3‬‬

‫;]‪myArrays[0] = new int[3‬‬


‫;]‪myArrays[1] = new int[5‬‬
‫;]‪myArrays[2] = new int[2‬‬

‫ابتدا با استفاده از کلمه کلیدی ‪ new‬سطرهای آرایه را مشخص میکنیم‪ .‬بعد از کلمه کلیدی ‪ new‬نوع آرایه و سپس در اولین کروشه باز و بسته تعداد سطرها را‬
‫مینویسیم‪ .‬سپس تعداد ستونهای هر سطر را با استفاده از اندیس هر سطر به صورت باال مشخص میکنیم‪ .‬سپس بعد از تعریف ستونها به صورت زیر میتوان‬
‫با استفاده از آکوالد مقادیر هر سطر را مشخص کرد ‪:‬‬

‫;][]‪int[][] myArrays = new int[3‬‬

‫;} ‪myArrays[0] = new int[3] { 1, 2, 3‬‬


‫;} ‪myArrays[1] = new int[5] { 5, 4, 3, 2, 1‬‬
‫;} ‪myArrays[2] = new int[2] { 11, 22‬‬

‫یک روش بهتر برای مقدار دهی آرایههای دندانه دار به صورت زیر است ‪:‬‬

‫‪int[][] myArrays = new int[3][] { new int[3] { 1, 2, 3 },‬‬


‫‪new int[5] { 5, 4, 3, 2, 1 },‬‬
‫;} } ‪new int[2] { 11, 22‬‬

‫میتوان طول سطرها را هم مشخص نکرد ‪:‬‬

‫‪int[][] myArrays = new int[][] { new int[] { 1, 2, 3 },‬‬


‫‪new int[] { 5, 4, 3, 2, 1 },‬‬
‫;} } ‪new int[] { 11, 22‬‬

‫‪97‬‬
‫کد باال را به صورت سادهتر زیر هم میتوان نوشت ‪:‬‬

‫‪int[][] myArrays = { new int[] { 1, 2, 3 },‬‬


‫‪new int[] { 5, 4, 3, 2, 1 },‬‬
‫;} } ‪new int[] { 11, 22‬‬

‫برای دسترسی به مقدار عناصر یک آرایه دندانه دار باید اندیس سطر و ستون آن را در اختیار داشته باشیم ‪:‬‬

‫]‪array[row][column‬‬
‫;)]‪Console.WriteLine(myArrays[1][2‬‬

‫نمیتوان از حلقه ‪ foreach‬برای دسترسی به عناصر آرایه دندانه دار استفاده کرد ‪:‬‬

‫)‪foreach(int array in myArrays‬‬


‫{‬
‫;)‪Console.WriteLine(array‬‬
‫}‬

‫اگر از حلقه ‪ foreach‬استفاده کنیم با خطا مواجه میشویم چون عناصر این نوع آرایهها‪ ،‬آرایه هستند نه عدد یا رشته یا… ‪ .‬برای حل این مشکل باید نوع متغیر‬
‫موقتی (‪ )array‬را تغییر داده و از حلقه ‪ foreach‬دیگری برای دسترسی به مقادیر استفاده کرد‪.‬‬

‫)‪foreach(int[] array in myArrays‬‬


‫{‬
‫)‪foreach(int number in array‬‬
‫{‬
‫;)‪Console.WriteLine(number‬‬
‫}‬
‫}‬

‫همچنین میتوان از یک حلقه ‪ for‬تو در تو به صورت زیر استفاده کرد ‪:‬‬

‫)‪for (int row = 0; row < myArrays.Length; row++‬‬


‫{‬
‫)‪for (int col = 0; col < myArrays[row].Length; col++‬‬
‫{‬
‫;)]‪Console.WriteLine(myArrays[row][col‬‬
‫}‬
‫}‬

‫در اولین حلقه از خاصیت ‪ Length‬برای به دست آوردن تعداد سطرها (که همان آرایههای یک بعدی هستند) و در دومین حلقه از خاصیت ‪ Length‬برای به‬
‫دست آوردن عناصر سطر جاری استفاده میشود‪.‬‬

‫متد‬

‫متدها به شما اجازه میدهند که یک رفتار یا وظیفه را تعریف کنید و مجموعهای از کدها هستند که در هر جای برنامه میتوان از آنها استفاده کرد‪ .‬متدها دارای‬
‫آرگومانهایی هستند که وظیفه متد را مشخص میکنند‪ .‬متد در داخل کالس تعریف میشود‪ .‬نمیتوان یک متد را در داخل متد دیگر تعریف کرد‪ .‬وقتی که شما در‬

‫‪98‬‬
‫برنامه یک متد را صدا میزنید برنامه به قسمت تعریف متد رفته و کدهای آن را اجرا میکند‪ .‬در سی شارپ متدی وجود دارد که نقطه آغاز هر برنامه است و بدون‬
‫آن برنامهها نمیدانند با ید از کجا شروع شوند‪ ،‬این متد )(‪ Main‬نام دارد‪.‬‬
‫پارامترها همان چیزهایی هستند که متد منتظر دریافت آنها است‪.‬‬
‫آرگومانها مقادیری هستند که به پارامترها ارسال میشوند‪.‬‬
‫گاهی اوقات دو کلمه پارامتر و آرگومان به یک منظور به کار میروند‪ .‬سادهترین ساختار یک متد به صورت زیر است ‪:‬‬

‫)‪returnType MethodName(Parameter List‬‬


‫{‬
‫;‪code to execute‬‬
‫}‬

‫به برنامه ساده زیر توجه کنید‪ .‬در این برنامه از یک متد برای چاپ یک پیغام در صفحه نمایش استفاده شده است ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪static void PrintMessage‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;)"!‪Console.WriteLine("Hello World‬‬
‫‪8:‬‬ ‫}‬
‫‪9:‬‬
‫‪10:‬‬ ‫)(‪public static void Main‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫;)(‪PrintMessage‬‬
‫‪13:‬‬ ‫}‬
‫} ‪14:‬‬

‫!‪Hello World‬‬
‫در خطوط ‪ 5-8‬یک متد تعریف کردهایم‪ .‬مکان تعریف آن در داخل کالس مهم نیست‪ .‬به عنوان مثال میتوانید آن را زیر متد )(‪ Main‬تعریف کنید‪ .‬میتوان‬
‫این متد را در داخل متد دیگر صدا زد (فراخوانی کرد)‪ .‬متد دیگر ما در اینجا متد )(‪ Main‬است که میتوانیم در داخل آن نام متدی که برای چاپ یک پیغام‬
‫تعریف کردهایم (یعنی متد )(‪ )PrintMessage‬را صدا بزنیم‪ .‬متد )(‪ Main‬به صورت ‪ static‬تعریف شده است‪ .‬برای اینکه بتوان از متد‬
‫)(‪PrintMessage‬در داخل متد )(‪ Main‬استفاده کنیم باید آن را به صورت ‪ static‬تعریف کنیم‪.‬‬
‫کلمه ‪ static‬به طور ساده به این معناست که میتوان از متد استفاده کرد بدون اینکه از کالس نمونهای ساخته شود‪ .‬متد )(‪ Main‬همواره باید به صورت‬
‫‪ static‬تعریف شود چون برنامه فوراً و بدون نمونه سازی از کالس از آن استفاده میکند‪ .‬وقتی به مبحث برنامه نویسی شی گرا رسیدید به طور دقیق کلمه‬
‫‪static‬مورد بحث قرار میگیرد‪ .‬برنامه ‪(class‬مثال باال) زمانی اجرا میشود که برنامه دو متدی را که تعریف کردهایم را اجرا کند و متد )(‪ Main‬به صورت‬
‫‪ static‬تعریف شود‪ .‬درباره این کلمه کلیدی در درسهای آینده مطالب بیشتری میآموزیم‪ .‬در تعریف متد باال بعد از کلمه ‪ static‬کلمه کلیدی ‪ void‬آمده است‬
‫که نشان دهنده آن است که متد مقدار برگشتی ندارد‪ .‬در درس آینده در مورد مقدار برگشتی از یک متد و استفاده از آن برای اهداف مختلف توضیح داده خواهد‬
‫است‪.‬‬ ‫)(‪PrintMessage‬‬ ‫ما‬ ‫متد‬ ‫نام‬ ‫شد‪.‬‬
‫به این نکته توجه کنید که در نامگذاری متد از روش پاسکال (حرف اول هر کلمه بزرگ نوشته میشود) استفاده کردهایم‪ .‬این روش نامگذاری قراردادی است و‬
‫میتوان از این روش استفاده نکرد‪ ،‬اما پیشنهاد می شود که از این روش برای تشخیص متدها استفاده کنید‪ .‬بهتر است در نامگذاری متدها از کلماتی استفاده شود‬
‫که کاران متد را مشخص میکند مثالً نامهایی مانند ‪ GoToBed‬یا ‪ . OpenDoor‬همچنین به عنوان مثال اگر مقدار برگشتی متد یک مقدار بولی باشد‬
‫میتوانید اسم متد خود را به صورت یک کلمه سوالی انتخاب کنید مانند ‪ IsLeapyear‬یا ‪…IsTeenager‬ولی از کذاشتن عالمت سؤال در آخر اسم متد‬
‫خودداری کنید‪ .‬دو پرانتزی که بعد از نام می آید نشان دهنده آن است که نام متعلق به یک متد است‪ .‬در این مثال در داخل پرانتزها هیچ چیزی نوشته نشده چون‬
‫میدهیم‪.‬‬ ‫توضیح‬ ‫بیشتر‬ ‫متدها‬ ‫مورد‬ ‫در‬ ‫آینده‬ ‫درسهای‬ ‫در‬ ‫ندارد‪.‬‬ ‫پارامتری‬
‫‪99‬‬
‫بعد از پرانتزها دو آکوالد قرار میدهیم که بدنه متد را تشکیل میدهد و کدهایی را که میخواهیم اجرا شوند را در داخل این آکوالدها مینویسیم‪ .‬در داخل متد‬
‫)(‪ Main‬متدی را که در خط ‪ 12‬ایجاد کردهایم را صدا میزنیم‪ .‬برای صدا زدن یک متد کافیست نام آن را نوشته و بعد از نام پرانتزها را قرار دهیم‪.‬‬
‫اگر متد دارای پارامتر باشد باید شما آرگومانها را به ترتیب در داخل پرانتزها قرار دهید‪ .‬در این مورد نیز در درسهای آینده توضیح بیشتری میدهیم‪ .‬با صدا زدن‬
‫یک متد کدهای داخل بدنه آن اجرا میشوند‪ .‬برای اجرای متد )(‪ PrintMessage‬برنامه از متد )(‪ Main‬به محل تعریف متد )(‪ PrintMessage‬میرود‪.‬‬
‫مثالً وقتی ما متد )(‪ PrintMessage‬را در خط ‪ 12‬صدا میزنیم برنامه از خط ‪ 12‬به خط ‪ ،7‬یعنی جایی که متد تعریف شده میرود‪ .‬اکنون ما یک متد در‬
‫برنامه ‪ class‬داریم و همه متدهای این برنامه میتوانند آن را صدا بزنند‪.‬‬

‫مقدار برگشتی از یک متد‬

‫متدها میتوانند مقدار برگشتی از هر نوع دادهای داشته باشند‪ .‬این مقادیر می توانند در محاسبات یا به دست آوردن یک داده مورد استفاده قرار بگیرند‪ .‬در زندگی‬
‫روزمره فرض کنید که کارمند شما یک متد است و شما او را صدا میزنید و از او میخواهید که کار یک سند را به پایان برساند‪ .‬سپس از او میخواهید که بعد از‬
‫اتمام کارش سند را به شما تحویل دهد‪ .‬سند همان مقدار برگشتی متد است‪ .‬نکته مهم در مورد یک متد‪ ،‬مقدار برگشتی و نحوه استفاده شما از آن است‪ .‬برگشت‬
‫یک مقدار از یک متد آسان است‪ .‬کافیست در تعریف متد به روش زیر عمل کنید ‪:‬‬

‫)(‪returnType MethodName‬‬
‫{‬
‫;‪return value‬‬
‫}‬

‫‪ returnType‬در اینجا نوع دادهای مقدار برگشتی را مشخص میکند (‪ .)…،bool،int‬در داخل بدنه متد کلمه کلیدی ‪ return‬و بعد از آن یک مقدار یا‬
‫عبارتی که نتیجه آن یک مقدار است را مینویسیم‪ .‬نوع این مقدار برگشتی باید از انواع ساده بوده و در هنگام نامگذاری متد و قبل از نام متد ذکر شود‪ .‬اگر متد ما‬
‫مقدار برگشتی نداشته باشد باید از کلمه ‪ void‬قبل از نام متد استفاده کنیم‪ .‬مثال زیر یک متد که دارای مقدار برگشتی است را نشان میدهد‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪static int CalculateSum‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪int firstNumber = 10‬‬
‫‪8:‬‬ ‫;‪int secondNumber = 5‬‬
‫‪9:‬‬
‫‪10:‬‬ ‫;‪int sum = firstNumber + secondNumber‬‬
‫‪11:‬‬
‫‪12:‬‬ ‫;‪return sum‬‬
‫‪13:‬‬ ‫}‬
‫‪14:‬‬
‫‪15:‬‬ ‫)(‪public static void Main‬‬
‫‪16:‬‬ ‫{‬
‫‪17:‬‬ ‫;)(‪int result = CalculateSum‬‬
‫‪18:‬‬
‫‪19:‬‬ ‫;)‪Console.WriteLine("Sum is {0}.", result‬‬
‫‪20:‬‬ ‫}‬
‫} ‪21:‬‬

‫‪Sum is 15.‬‬

‫‪100‬‬
‫همانطور که در خط ‪ 5‬مثال فوق مشاهده میکنید هنگام تعریف متد از کلمه ‪ int‬به جای ‪ void‬استفاده کردهایم که نشان دهنده آن است که متد ما دارای مقدار‬
‫برگشتی از نوع اعداد صحیح است‪ .‬در خطوط ‪ 7‬و ‪ 8‬دو متغیر تعریف و مقدار دهی شدهاند‪.‬‬
‫توجه کنی د که این متغیرها‪ ،‬متغیرهای محلی هستند‪ .‬و این بدان معنی است که این متغیرها در سایر متدها مانند متد ‪ Main‬قابل دسترسی نیستند و فقط در‬
‫متدی که در آن تعریف شدهاند قابل استفاده هستند‪ .‬در خط ‪ 10‬جمع دو متغیر در متغیر ‪ sum‬قرار میگیرد‪ .‬در خط ‪ 12‬مقدار برگشتی ‪ sum‬توسط دستور‬
‫‪ return‬فراخوانی میشود‪ .‬در داخل متد ‪ Main‬یک متغیربه نام ‪ result‬در خط ‪ 17‬تعریف میکنیم و متد )(‪ CalculateSum‬را فراخوانی میکنیم‪.‬‬
‫متد )(‪ CalculateSum‬مقدار ‪ 158‬را بر میگرداند که در داخل متغیر ‪ result‬ذخیره میشود‪ .‬در خط ‪ 19‬مقدار ذخیره شده در متغیر ‪ result‬چاپ میشود‪.‬‬
‫متدی که در این مثال ذکر شد متد کاربردی و مفیدی نیست‪ .‬با وجودیکه کدهای زیادی در متد باال نوشته شده ولی همیشه مقدار برگشتی ‪ 15‬است‪ ،‬در حالیکه‬
‫میتوانستیم به راحتی یک متغیر تعریف کرده و مقدار ‪ 15‬را به آن اختصاص دهیم‪ .‬این متد در صورتی کارامد است که پارامترهایی به آن اضافه شود که در‬
‫درسهای آینده توضیح خواهیم داد‪ .‬هنگامی که میخواهیم در داخل یک متد از دستور ‪ if‬یا ‪ switch‬استفاده کنیم باید تمام کدها دارای مقدار برگشتی باشند‪.‬‬
‫برای درک بهتر این مطلب به مثال زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪static int GetNumber‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪int number‬‬
‫‪8:‬‬
‫‪9:‬‬ ‫;)" ‪Console.Write("Enter a number greater than 10:‬‬
‫‪10:‬‬ ‫;))(‪number = Convert.ToInt32(Console.ReadLine‬‬
‫‪11:‬‬
‫‪12:‬‬ ‫)‪if (number > 10‬‬
‫‪13:‬‬ ‫{‬
‫‪14:‬‬ ‫;‪return number‬‬
‫‪15:‬‬ ‫}‬
‫‪16:‬‬ ‫‪else‬‬
‫‪17:‬‬ ‫{‬
‫‪18:‬‬ ‫;‪return 0‬‬
‫‪19:‬‬ ‫}‬
‫‪20:‬‬ ‫}‬
‫‪21:‬‬
‫‪22:‬‬ ‫)(‪public static void Main‬‬
‫‪23:‬‬ ‫{‬
‫‪24:‬‬ ‫;)(‪int result = GetNumber‬‬
‫‪25:‬‬
‫‪26:‬‬ ‫;)‪Console.WriteLine("Result = {0}.", result‬‬
‫‪27:‬‬ ‫}‬
‫} ‪28:‬‬

‫‪Enter a number greater than 10: 11‬‬


‫‪Result = 11‬‬
‫‪Enter a number greater than 10: 9‬‬
‫‪Result = 0‬‬
‫در خطوط ‪ 20-5‬یک متد با نام )(‪ GetNumber‬تعریف شده است که از کاربر یک عدد بزرگتر از ‪ 10‬را میخواهد‪ .‬اگر عدد وارد شده توسط کاربر درست‬
‫نباشد متد مقدار صفر را بر میگرداند‪ .‬و اگر قسمت ‪ else‬دستور ‪if‬و یا دستور ‪ return‬را از آن حذف کنیم در هنگام اجرای برنامه با پیغام خطا مواجه میشویم‪.‬‬

‫‪101‬‬
‫چون اگر شرط دستور ‪ if‬نادرست باشد (کاربر مقداری کمتر از ‪ 10‬را وارد کند) برنامه به قسمت ‪ else‬میرود تا مقدار صفر را بر گرداند و چون قسمت ‪else‬‬
‫حذف شده است برنامه با خطا مواجه میشود و همچنین اگر دستور ‪ return‬حذف شود چون برنامه نیاز به مقدار برگشتی دارد پیغام خطا میدهد‪ .‬و آخرین‬
‫مطلبی که در این درس میخواهیم به شما آموزش دهیم این است که شما میتوانید از یک متد که مقدار برگشتی ندارد خارج شوید‪ .‬حتی اگر از نوع دادهای‬
‫‪ void‬در یک متد استفاده میکنید باز هم میتوانید کلمه کلیدی ‪ return‬را در آن به کار ببرید‪ .‬استفاده از ‪ return‬باعث خروج از بدنه متد و اجرای کدهای بعد‬
‫از آن میشود‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪static void TestReturnExit‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;)")(‪Console.WriteLine("Line 1 inside the method TestReturnExit‬‬
‫‪8:‬‬ ‫;)")(‪Console.WriteLine("Line 2 inside the method TestReturnExit‬‬
‫‪9:‬‬
‫‪10:‬‬ ‫;‪return‬‬
‫‪11:‬‬
‫‪12:‬‬ ‫‪//The following lines will not execute‬‬
‫‪13:‬‬ ‫;)")(‪Console.WriteLine("Line 3 inside the method TestReturnExit‬‬
‫‪14:‬‬ ‫;)")(‪Console.WriteLine("Line 4 inside the method TestReturnExit‬‬
‫‪15:‬‬ ‫}‬
‫‪16:‬‬
‫‪17:‬‬ ‫)(‪public static void Main‬‬
‫‪18:‬‬ ‫{‬
‫‪19:‬‬ ‫;)(‪TestReturnExit‬‬
‫‪20:‬‬ ‫;)"!‪Console.WriteLine("Hello World‬‬
‫‪21:‬‬ ‫}‬
‫} ‪22:‬‬

‫)(‪Line 1 inside the method TestReturnExit‬‬


‫)(‪Line 2 inside the method TestReturnExit‬‬
‫!‪Hello World‬‬
‫در برنامه باال نحوه خروج از متد با استفاده از کلمه کلیدی ‪ return‬و نادیده گرفتن همه کدهای بعد از این کلمه کلیدی نشان داده شده است‪ .‬در پایان‬
‫برنامه متد تعریف شده ()(‪ )TestReturnExit‬در داخل متد )(‪ Main‬فراخوانی و اجرا میشود‪.‬‬

‫پارامترها و آرگومان ها‬

‫پارامترها دادههای خامی هستند که متد آنها را پردازش میکند و سپس اطالعاتی را که به دنبال آن هستید‪ ،‬در اختیار شما قرار میدهد‪ .‬فرض کنید پارامترها مانند‬
‫اطالعاتی هستند که شما به یک کارمند میدهید که بر طبق آنها کارش را به پایان برساند‪ .‬یک متد میتواند هر تعداد پارامتر داشته باشد‪ .‬هر پارامتر میتواند از‬
‫انواع مختلف داده باشد‪ .‬در زیر یک متد با ‪ N‬پارامتر نشان داده شده است ‪:‬‬

‫)‪returnType MethodName(datatype param1, datatype param2, ... datatype paramN‬‬


‫{‬
‫;‪code to execute‬‬
‫}‬

‫‪102‬‬
‫پارامترها بعد از نام متد و بین پرانتزها قرار میگیرند‪ .‬بر اساس کاری که متد انجام میدهد میتوان تعداد پارامترهای زیادی به متد اضافه کرد‪ .‬بعد از فراخوانی یک‬
‫متد باید آرگومانهای آن را نیز تأمین کنید‪ .‬آرگومانها مقادیری هستند که به پارامترها اختصاص داده میشوند‪ .‬ترتیب ارسال آرگومانها به پارامترها مهم است‪ .‬عدم‬
‫رعایت ترتیب در ارسال آرگومانها باعث به وجود آمدن خطای منطقی و خطای زمان اجرا میشود‪ .‬اجازه بدهید که یک مثال بزنیم ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)‪static int CalculateSum(int number1, int number2‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪return number1 + number2‬‬
‫‪8:‬‬ ‫}‬
‫‪9:‬‬
‫‪10:‬‬ ‫)(‪public static void Main‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫;‪int num1, num2‬‬
‫‪13:‬‬
‫‪14:‬‬ ‫;)" ‪Console.Write("Enter the first number:‬‬
‫‪15:‬‬ ‫;))(‪num1 = Convert.ToInt32(Console.ReadLine‬‬
‫‪16:‬‬ ‫;)" ‪Console.Write("Enter the second number:‬‬
‫‪17:‬‬ ‫;))(‪num2 = Convert.ToInt32(Console.ReadLine‬‬
‫‪18:‬‬
‫‪19:‬‬ ‫;))‪Console.WriteLine("Sum = {0}", CalculateSum(num1, num2‬‬
‫‪20:‬‬ ‫}‬
‫} ‪21:‬‬

‫‪Enter the first number: 10‬‬


‫‪Enter the second number: 5‬‬
‫‪Sum = 15‬‬
‫در برنامه باال یک متد به نام )(‪( CalculateSum‬خطوط ‪ ) 5-8‬تعریف شده است که وظیفه آن جمع مقدار دو عدد است‪ .‬چون این متد مقدار دو عدد صحیح‬
‫را با هم جمع میکند پس نوع برگشتی ما نیز باید ‪ int‬باشد‪ .‬متد دارای دو پارامتر است که اعداد را به آنها ارسال میکنیم‪ .‬به نوع دادهای پارامترها توجه کنید‪ .‬هر‬
‫دو پارامتر یعنی ‪ number1‬و ‪ number2‬مقادیری از نوع اعداد صحیح (‪ )int‬دریافت میکنند‪ .‬در بدنه متد دستور ‪ return‬نتیجه جمع دو عدد را بر‬
‫میگرداند‪ .‬در داخل متد ‪ Main‬برنامه از کاربر دو مقدار را درخواست میکند و آنها را داخل متغیرها قرار میدهد‪ .‬حال متد را که آرگومانهای آن را آماده کردهایم‬
‫فراخوانی میکنیم‪ .‬مقدار ‪ num1‬به پارامتر اول و مقدار ‪ num2‬به پارامتر دوم ارسال می شود‪ .‬حال اگر مکان دو مقدار را هنگام ارسال به متد تغییر دهیم (یعنی‬
‫مقدار ‪ num2‬به پارامتر اول و مقدار ‪ num1‬به پارامتر دوم ارسال شود) هیچ تغییری در نتیجه متد ندارد چون جمع خاصیت جابه جایی دارد‪.‬‬
‫فقط به یاد داشته باشید که باید ترتیب ارسال آرگومانها هنگام فراخوانی متد دقیقاً با ترتیب قرار گیری پارامترها تعریف شده در متد مطابقت داشته باشد‪ .‬بعد از‬
‫ارسال مقادیر ‪ 10‬و ‪ 5‬به پارامترها‪ ،‬پارامترها آنها را دریافت میکنند‪ .‬به این نکته نیز توجه کنید که نام پارامترها طبق قرارداد به شیوه کوهان شتری یا‬
‫‪( camelCasing‬حرف اول دومین کلمه بزرگ نوشته میشود) نوشته میشود‪ .‬در داخل بدنه متد (خط ‪ )7‬دو مقدار با هم جمع میشوند و نتیجه به متد فراخوان‬
‫(متدی که متد)(‪ CalculateSum‬را فراخوانی میکند) ارسال میشود‪ .‬در درس آینده از یک متغیر برای ذخیره نتیجه محاسبات استفاده میکنیم ولی در اینجا‬
‫مشاهده میکنید که میتوان به سادگی نتیجه جمع را نشان داد (خط ‪ .)7‬در داخل متد ‪ Main‬از ما دو عدد که قرار است با هم جمع شوند درخواست میشود‪.‬‬
‫در خط ‪ 19‬متد )(‪ CalculateSum‬را فراخوانی میکنیم و دو مقدار صحیح به آن ارسال میکنیم‪ .‬دو عدد صحیح در داخل متد با هم جمع شده و نتیجه آنها‬
‫برگردانده میشود‪ .‬مقدار برگشت داده شده از متد به وسیله متد )(‪ WriteLine‬از کالس ‪ Console‬نمایش داده میشود‪( .‬خط ‪ )19‬در برنامه زیر یک متد‬
‫تعریف شده است که دارای دو پارامتر از دو نوع دادهای مختلف است‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬

‫‪103‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)‪static void ShowMessageAndNumber(string message, int number‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;)‪Console.WriteLine(message‬‬
‫‪8:‬‬ ‫;)‪Console.WriteLine("Number = {0}", number‬‬
‫‪9:‬‬ ‫}‬
‫‪10:‬‬
‫‪11:‬‬ ‫)(‪public static void Main‬‬
‫‪12:‬‬ ‫{‬
‫‪13:‬‬ ‫;)‪ShowMessageAndNumber("Hello World!", 100‬‬
‫‪14:‬‬ ‫}‬
‫} ‪15:‬‬

‫!‪Hello World‬‬
‫‪Number = 100‬‬
‫در مثال باال یک متدی تعریف شده است که اولین پارامتر آن مقداری از نوع رشته و دومین پارامتر آن مقداری از نوع ‪ int‬دریافت میکند‪ .‬متد به سادگی دو‬
‫مقداری که به آن ارسال شده است را نشان میدهد‪ .‬در خط ‪ 13‬متد را اول با یک رشته و سپس یک عدد خاص فراخوانی میکنیم‪ .‬حال اگر متد به صورت زیر‬
‫فراخوانی میشد ‪:‬‬

‫;)"!‪ShowMessageAndNumber(100, "Welcome to Gimme C#‬‬

‫در برنامه خطا به وجود میآمد چون عدد ‪ 100‬به پارامتری از نوع رشته و رشته !‪ Hello World‬به پارامتری از نوع اعداد صحیح ارسال میشد‪ .‬این نشان‬
‫میدهد که ترتیب ارسال آرگومانها به پارامترها هنگام فراخوانی متد مهم است‪ .‬به مثال ‪ 1‬توجه کنید در آن مثال دو عدد از نوع ‪ int‬به پارامترها ارسال کردیم که‬
‫ترتیب ارسال آنها چون هردو پارامتر از یک نوع بودند مهم نبود‪ .‬ولی اگر پارامترهای متد دارای اهداف خاصی باشند ترتیب ارسال آرگومانها مهم است‪.‬‬

‫)‪void ShowPersonStats(int age, int height‬‬


‫{‬
‫;)‪Console.WriteLine("Age = {0}", age‬‬
‫;)‪Console.WriteLine("Height = {0}", height‬‬
‫}‬

‫‪//Using the proper order of arguments‬‬


‫;)‪ShowPersonStats(20, 160‬‬

‫‪//Acceptable, but produces odd results‬‬


‫;)‪ShowPersonStats(160, 20‬‬

‫در مثال باال نشان داده شده است که حتی اگر متد دو آرگومان با یک نوع داده ای قبول کند باز هم بهتر است ترتیب بر اساس تعریف پارامترها رعایت شود‪ .‬به‬
‫عنوان مثال در اولین فراخوانی متد باال اشکالی به چشم نمیآید چون سن شخص ‪ 20‬و قد او ‪ 160‬سانتی متر است‪ .‬اگر آرگومانها را به ترتیب ارسال نکنیم سن‬
‫شخص ‪ 160‬و قد او ‪ 20‬سانتی متر می شود که به واقعیت نزدیک نیست‪ .‬دانستن مبانی مقادیر برگشتی و ارسال آرگومانها باعث میشود که شما متدهای کارامد‬
‫تری تعریف کنید‪ .‬تکه کد زیر نشان میدهد که شما حتی میتوانید مقدار برگشتی از یک متد را به عنوان آرگومان به متد دیگر ارسال کنید‪.‬‬

‫)(‪int MyMethod‬‬
‫{‬
‫;‪return 5‬‬
‫}‬

‫)‪void AnotherMethod(int number‬‬


‫{‬

‫‪104‬‬
‫;)‪Console.WriteLine(number‬‬
‫}‬

‫‪// Codes skipped for demonstration‬‬

‫;))(‪AnotherMethod(MyMethod‬‬

‫چون مقدار برگشتی متد )(‪ MyMethod‬عدد ‪ 5‬است و به عنوان آرگومان به متد )(‪ AnotherMethod‬ارسال میشود خروجی کد باال هم عدد ‪5‬‬
‫است‪.‬‬

‫نامیدن آرگومان ها‬

‫یکی دیگر از راه های ارسال آرگومانها استفاده از نام آنهاست‪ .‬استفاده از نام آرگومانها شما را از به یاد آوری و رعایت ترتیب پارامترها هنگام ارسال آرگومانها‬
‫راحت میکند‪ .‬در عوض شما باید نام پارامترهای متد را به خاطر بسپارید (ولی از آن جاییکه ویژوال استودیو ‪ Intellisense‬دارد نیازی به این کار نیست‪).‬‬
‫استفاده از نام آرگومانها خوانایی برنامه را باال میبرد چون شما میتوانید ببینید که چه مقادیری به چه پارامترهایی اختصاص داده شده است‪.‬‬
‫نامیدن آرگومانها در سی شارپ ‪ 2010‬مطرح شده است و اگر شما از نسخههای قبلی مانند سی شارپ ‪ 2008‬استفاده میکنید نمیتوانید از این خاصیت استفاده‬
‫کنید‪ .‬در زیر نحوه استفاده از نام آرگومانها وقتی که متد فراخوانی میشود نشان داده شده است ‪:‬‬

‫;)‪MethodToCall( paramName1: value, paramName2: value, ... paramNameN: value‬‬

‫حال به مثال زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)‪static void SetSalaries(decimal jack, decimal andy, decimal mark‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;)‪Console.WriteLine("Jack's salary is {0:C}.", jack‬‬
‫‪8:‬‬ ‫;)‪Console.WriteLine("Andy's salary is {0:C}.", andy‬‬
‫‪9:‬‬ ‫;)‪Console.WriteLine("Mark's salary is {0:C}.", mark‬‬
‫‪10:‬‬ ‫}‬
‫‪11:‬‬
‫‪12:‬‬ ‫)(‪public static void Main‬‬
‫‪13:‬‬ ‫{‬
‫‪14:‬‬ ‫;)‪SetSalaries(jack: 120, andy: 30, mark: 75‬‬
‫‪15:‬‬
‫‪16:‬‬ ‫‪//Print a newline‬‬
‫‪17:‬‬ ‫;)(‪Console.WriteLine‬‬
‫‪18:‬‬
‫‪19:‬‬ ‫;)‪SetSalaries(andy: 60, mark: 150, jack: 50‬‬
‫‪20:‬‬
‫‪21:‬‬ ‫;)(‪Console.WriteLine‬‬
‫‪22:‬‬
‫‪23:‬‬ ‫;)‪SetSalaries(mark: 35, jack: 80, andy: 150‬‬
‫‪24:‬‬ ‫}‬
‫} ‪25:‬‬

‫‪105‬‬
‫‪Jack's salary is $120.‬‬
‫‪Andy's salary is $30.‬‬
‫‪Mark's salary is $75.‬‬

‫‪Jack's salary is $50.‬‬


‫‪Andy's salary is $60.‬‬
‫‪Mark's salary is $150.‬‬

‫‪Jack's salary is $80.‬‬


‫‪Andy's salary is $150.‬‬
‫‪Mark's salary is $35.‬‬
‫متد )(‪ WriteLine‬در خطوط ‪ 7-9‬از فرمت پول رایج که با }‪ {0:C‬نشان داده میشود استفاده کرده است که یک داده عددی را به نوع پولی تبدیل میکند‪.‬‬
‫خروجی نشان میدهد که حتی اگر ما ترتیب آرگومانها در سه متد فراخوانی شده را تغییر دهیم مقادیر مناسب به پارامترهای مربوطهشان اختصاص داده میشود‪.‬‬
‫همچنین می توان از آرگومانهای دارای نام و آرگومانهای ثابت (مقداری) به طور همزمان استفاده کرد به شرطی که آرگومانهای ثابت قبل از آرگومانهای دارای نام‬
‫قرار بگیرند‪.‬‬

‫‪//Assign 30 for Jack's salary and use named arguments for‬‬


‫‪// the assignment of the other two‬‬

‫;)‪SetSalary(30, andy: 50, mark: 60‬‬

‫‪// or‬‬

‫;)‪SetSalary(30, mark: 60, andy: 50‬‬

‫‪//The following codes are wrong and will lead to errors‬‬

‫;)‪SetSalary(mark: 60, andy: 50, 30‬‬

‫‪// and‬‬

‫;)‪SetSalary(mark: 60, 30, andy: 50‬‬

‫همانطور که مشاهده می کنید ابتدا باید آرگومانهای ثابت هنگام فراخوانی متد ذکر شوند‪ .‬در اولین و دومین فراخوانی در کد باال‪ ،‬مقدار ‪ 30‬را به عنوان اولین‬
‫آرگومان به اولین پارامتر متد یعنی ‪ jack‬اختصاص میدهیم‪ .‬سومین و چهارمین خط کد باال اشتباه هستند چون آرگومانهای دارای نام قبل از آرگومانهای‬
‫ثابت قرار گرفتهاند‪ .‬قرار گرفتن آرگومانهای دارای نام بعد از آرگومانها ثابت از بروز خطا جلوگیری میکند‬

‫ارسال آرگومان ها به روش ارجاع‬

‫آرگومانها را می توان به کمک ارجاع ارسال کرد‪ .‬این بدان معناست که شما آدرس متغیری را ارسال میکنید نه مقدار آن را‪ .‬ارسال با ارجاع زمانی مفید است که‬
‫شما بخواهید یک آرگومان که دارای مقدار بزرگی است (مانند یک آبجکت) را ارسال کنید‪ .‬در این حالت وقتی که آرگومان ارسال شده را در داخل متد اصالح‬
‫میکند‪.‬‬ ‫تغییر‬ ‫هم‬ ‫متد‬ ‫از‬ ‫خارج‬ ‫در‬ ‫آرگومان‬ ‫اصلی‬ ‫مقدار‬ ‫میکنیم‬
‫در زیر دستورالعمل پایهای تعریف پارامترها که در آنها به جای مقدار از آدرس استفاده شده است نشان داده شده ‪:‬‬

‫)‪returnType MethodName(ref datatype param1‬‬


‫{‬
‫;‪code to execute‬‬

‫‪106‬‬
}

‫ استفاده‬ref ‫ وقتی یک متد فراخوانی میشود و آرگومانها به آنها ارسال میشود هم باید از کلمه کلیدی‬.‫ استفاده کنید‬ref ‫فراموش نشود که باید از کلمه کلیدی‬
.‫شود‬

MethodName(ref argument);

.‫اجازه دهید که تفاوت بین ارسال با ارجاع و ارسال با مقدار آرگومان را با یک مثال توضیح دهیم‬

1: using System;
2:
3: public class Program
4: {
5: static void ModifyNumberVal(int number)
6: {
7: number += 10;
8: Console.WriteLine("Value of number inside method is {0}.", number);
9: }
10:
11: static void ModifyNumberRef(ref int number)
12: {
13: number += 10;
14: Console.WriteLine("Value of number inside method is {0}.", number);
15: }
16:
17: public static void Main()
18: {
19: int num = 5;
20:
21: Console.WriteLine("num = {0}n", num);
22:
23: Console.WriteLine("Passing num by value to method ModifyNumberVal() ...");
24: ModifyNumberVal(num);
25: Console.WriteLine("Value of num after exiting the method is {0}.n", num);
26:
27: Console.WriteLine("Passing num by ref to method ModifyNumberRef() ...");
28: ModifyNumberRef(ref num);
29: Console.WriteLine("Value of num after exiting the method is {0}.n", num);
30: }
31: }

num = 5

Passing num by value to method ModifyNumberVal() ...


Value of number inside method is 15.
Value of num after exiting the method is 5.

Passing num by ref to method ModifyNumberRef() ...


Value of number inside method is 15.
Value of num after exiting the method is 15.

107
‫در برنامه باال دو متد که دارای یک هدف یکسان هستند تعریف شدهاند و آن اضافه کردن عدد ‪ 10‬به مقداری است که به آنها ارسال میشود‪ .‬اولین متد (خطوط‬
‫‪ )9-5‬دارای یک پارامتر است که نیاز به یک مقدار آرگومان (از نوع ‪ )int‬دارد‪ .‬وقتی که متد را صدا میزنیم و آرگومانی به آن اختصاص میدهیم (خط ‪ ،)24‬کپی‬
‫آرگومان به پارامتر متد ارسال میشود‪ .‬بنابراین مقدار اصلی متغیر خارج از متد هیچ ارتباطی به پارامتر متد ندارد‪ .‬سپس مقدار ‪ 10‬را به متغیر پارامتر (‪)number‬‬
‫میکنیم‪.‬‬ ‫چاپ‬ ‫را‬ ‫نتیجه‬ ‫و‬ ‫کرده‬ ‫اضافه‬
‫برای اثبات اینکه متغیر ‪ num‬هیچ تغییری نکرده است مقدار آن را یکبار دیگر چاپ کرده و مشاهده میکنیم که تغییری نکرده است‪ .‬دومین متد (خطوط ‪-15‬‬
‫‪ ) 11‬نیاز به یک مقدار با ارجاع دارد‪ .‬در این حالت به جای اینکه یک کپی از مقدار به عنوان آرگومان به ان ارسال شود آدرس متغیر به آن ارسال میشود‪ .‬حال‬
‫پارامتر به مقدار اصلی متغیر که زمان فراخوانی متد به آن ارسال میشود دسترسی دارد‪ .‬وقتی که ما مقدار متغیر پارامتری که شامل آدرس متغیر اصلی است را‬
‫تغییر میدهیم (خط ‪ )13‬در واقع مقدار متغیر اصلی در خارج از متد را تغییر دادهایم‪ .‬در نهایت مقدار اصلی متغیر را وقتی که از متد خارج شدیم را نمایش میدهیم‬
‫و مشاهده میشود که مقدار آن واقعاً تغییر کرده است‪.‬‬

‫پارامترهای ‪out‬‬

‫پارامترهای ‪ out‬پارامترهایی هستند که متغیرهایی را که مقدار دهی اولیه نشدهاند را قبول میکنند‪ .‬کلمه کلیدی ‪ out‬زمانی مورد استفاده قرار میگیرد که‬
‫بخواهیم یک متغیر بدون مقدار را به متد ارسال کنیم‪ .‬متغیر بدون مقدار اولیه‪ ،‬متغیری است که مقداری به آن اختصاص داده نشده است‪ .‬در این حالت متد یک‬
‫مقدار به متغیر میدهد‪ .‬ارسال متغیر مقداردهی نشده به متد زمانی مفید است که شما بخواهید از طریق متد متغیر را مقدار دهی کنید‪ .‬استفاده از کلمه کلیدی ‪out‬‬
‫باعث ارسال آرگومان به روش ارجاع میشود نه مقدار‪ .‬به مثال زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)‪static void GiveValue(out int number‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪number = 10‬‬
‫‪8:‬‬ ‫}‬
‫‪9:‬‬
‫‪10:‬‬ ‫)(‪public static void Main‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫‪//Uninitialized variable‬‬
‫‪13:‬‬ ‫;‪int myNumber‬‬
‫‪14:‬‬
‫‪15:‬‬ ‫;)‪GiveValue(out myNumber‬‬
‫‪16:‬‬
‫‪17:‬‬ ‫;)‪Console.WriteLine("myNumber = {0}", myNumber‬‬
‫‪18:‬‬ ‫}‬
‫} ‪19:‬‬

‫‪myNumber = 10‬‬
‫از کلمه کلیدی ‪ out‬برای پارامترهای متد استفاده شده است بنابراین میتوانند متغیرهای مقداردهی نشده را قبول کنند‪ .‬در متد ‪ ، Main‬خط ‪ 15‬متد را فراخوانی‬
‫میکنیم و قبل از آرگومان کلمه کلیدی ‪ out‬را قرار میدهیم‪ .‬متغیر مقداردهی نشده (‪ )myNumber‬به متد ارسال میشود و در آنجا مقدار ‪ 10‬به آن اختصاص‬
‫داده میشود (خط ‪ .)7‬مقدار ‪myNumber‬در خط ‪ 17‬نمایش داده میشود و مشاهده میکنید که مقدارش برابر مقداری است که در داخل متد به آن اختصاص‬
‫داده شده است (یعنی ‪ .)10‬استفاده از پارامترهای ‪ out‬بدین معنا نیست که شما همیشه نیاز دارید که آرگومانهای مقداردهی نشده را به متد ارسال کنید بلکه‬
‫آرگومانهایی که شامل مقدار هستند را هم میتوان به متد ارسال کرد‪ .‬این کار درحکم استفاده از کلمه کلیدی ‪ ref‬است‪.‬‬

‫‪108‬‬
‫تفاوت ‪ ref‬با ‪ out‬این است که کلمه کلیدی ‪ ref‬به کامپایلر میگوید که متغیر مقدار دهی اولیه و بعد به متد ارسال شده است ولی ‪ out‬به کامپایلر میگوید که‬
‫متغیر مقدار دهی اولیه نشده و باید در داخل متد مقدار دهی اولیه شود‪.‬‬
‫همانطور که قبالً هم ذکر شد‪ ،‬معموالً متد از کلمه کلیدی ‪ return‬برای برگشت مقدار استفاده میکند‪ .‬متاسفانه این کلمه کلیدی فقط میتواند یک مقدار را‬
‫برگشت دهد‪ .‬گاهی اوقات الزم است که یک متد دارای چندین خروجی باشد‪ .‬اینجاست که از کلمه کلیدی ‪ out‬استفاده میشود‪ .‬به مثال زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)‪public static void Rectangle(int len, int width, out int area, out int perimeter‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪area = len * width‬‬
‫‪8:‬‬ ‫;)‪perimeter = 2 * (len + width‬‬
‫‪9:‬‬ ‫}‬
‫‪10:‬‬
‫‪11:‬‬ ‫)‪static void Main(string[] args‬‬
‫‪12:‬‬ ‫{‬
‫‪13:‬‬ ‫;‪int area, perimeter‬‬
‫‪14:‬‬
‫‪15:‬‬ ‫;)‪Program.Rectangle(5, 4, out area, out perimeter‬‬
‫‪16:‬‬
‫‪17:‬‬ ‫;)‪Console.WriteLine("Area of Rectangle is {0}\t", area‬‬
‫‪18:‬‬ ‫;)‪Console.WriteLine("Perimeter of Rectangle is {0}\t", perimeter‬‬
‫‪19:‬‬ ‫;)(‪Console.ReadLine‬‬
‫‪20:‬‬ ‫}‬
‫} ‪21:‬‬

‫‪Area of Rectangle is 20‬‬


‫‪Perimeter of Rectangle is 18‬‬
‫متد باال یعنی ()‪ Rectangle‬قرار است دو خروجی داشته باشد‪ .‬این دو خروجی محیط (‪ )area‬و مساحت (‪ )perimeter‬مستطیل میباشند‪ .‬در نتیجه قبل از‬
‫آنها و در قسمت پارامترهای متد (خط ‪ )5‬و هنگام فراخوانی متد کلمه کلیدی ‪ out‬را مینویسیم (خط ‪.)15‬‬

‫ارسال آرایه به عنوان آرگومان‬

‫میتوان آرایهها را به عنوان آرگومان به متد ارسال کرد‪ .‬ابتدا شما باید پارامترهای متد را طوری تعریف کنید که آرایه دریافت کنند‪ .‬به مثال زیر توجه کنید‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)‪static void TestArray(int[] numbers‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫)‪foreach (int number in numbers‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫;)‪Console.WriteLine(number‬‬
‫‪10:‬‬ ‫}‬
‫‪11:‬‬ ‫}‬
‫‪109‬‬
‫‪12:‬‬
‫‪13:‬‬ ‫)(‪public static void Main‬‬
‫‪14:‬‬ ‫{‬
‫‪15:‬‬ ‫;} ‪int[] array = { 1, 2, 3, 4, 5‬‬
‫‪16:‬‬
‫‪17:‬‬ ‫;)‪TestArray(array‬‬
‫‪18:‬‬ ‫}‬
‫} ‪19:‬‬

‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪5‬‬
‫مشاهده کردید که به سادگی میتوان با گذاشتن کروشه بعد از نوع دادهای پارامتر یک متد ایجاد کرد که پارامتر آن‪ ،‬آرایه دریافت میکند‪ .‬وقتی متد در خط ‪17‬‬
‫فراخوانی میشود‪ ،‬آرایه را فقط با استفاده از نام آن و بدون استفاده از اندیس ارسال میکنیم‪ .‬پس آرایهها هم به روش ارجاع به متدها ارسال میشوند‪ .‬در خطوط‬
‫‪ 10-7‬از حلقه ‪ foreach‬برای دسترسی به اجزای اصلی آرایه که به عوان آرگومان به متد ارسال کردهایم استفاده میکنیم‪ .‬در زیر نحوه ارسال یک آرایه به‬
‫روش ارجاع نشان داده شده است‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)‪static void IncrementElements(int[] numbers‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫)‪for (int i = 0; i < numbers.Length; i++‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫;‪numbers[i]++‬‬
‫‪10:‬‬ ‫}‬
‫‪11:‬‬ ‫}‬
‫‪12:‬‬
‫‪13:‬‬ ‫)(‪public static void Main‬‬
‫‪14:‬‬ ‫{‬
‫‪15:‬‬ ‫;} ‪int[] array = { 1, 2, 3, 4, 5‬‬
‫‪16:‬‬
‫‪17:‬‬ ‫;)‪IncrementElements(array‬‬
‫‪18:‬‬
‫‪19:‬‬ ‫)‪foreach (int num in array‬‬
‫‪20:‬‬ ‫{‬
‫‪21:‬‬ ‫;)‪Console.WriteLine(num‬‬
‫‪22:‬‬ ‫}‬
‫‪23:‬‬ ‫}‬
‫} ‪24:‬‬

‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪5‬‬
‫‪6‬‬
‫برنامه باال یک متد را نشان میدهد که یک آرایه را دریافت میکند و به هر یک از عناصر آن یک واحد اضافه میکند‪ .‬به این نکته توجه کنید که از حلقه‬
‫‪ foreach‬نمی توان برای افزایش مقادیر آرایه استفاده کنیم چون این حلقه برای خواندن مقادیر آرایه مناسب است نه اصالح آنها‪ .‬در داخل متد ما مقادیر هر یک‬

‫‪110‬‬
‫از اجزای آرایه را افزایش دادهایم‪ ..‬سپس از متد خارج شده و نتیجه را نشان میدهیم‪ .‬مشاهده میکنید که هر یک از مقادیر اصلی متد هم اصالح شدهاند‪ .‬راه دیگر‬
‫است‪.‬‬ ‫شده‬ ‫فراخوانی‬ ‫متد‬ ‫به‬ ‫مستقیم‬ ‫دهی‬ ‫مقدار‬ ‫متد‪،‬‬ ‫به‬ ‫آرایه‬ ‫ارسال‬ ‫برای‬
‫به عنوان مثال ‪:‬‬

‫;) } ‪IncrementElements( new int[] { 1, 2, 3, 4, 5‬‬

‫در این روش ما آرایهای تعریف نمیکنیم بلکه مجموعهای از مقادیر را به پارامتر ارسال میکنیم که آنها را مانند آرایه قبول کند‪ .‬از آنجاییکه در این روش آرایهای‬
‫تعریف نکردهایم نمیتوانیم در متد ‪ Main‬نتیجه را چاپ کنیم‪ .‬اگر از چندین پارامتر در متد استفاده میکنید همیشه برای هر یک از پارامترهایی که آرایه قبول‬
‫کنید‪.‬‬ ‫استفاده‬ ‫کروشه‬ ‫جفت‬ ‫یک‬ ‫از‬ ‫میکنند‬
‫به عنوان مثال ‪:‬‬

‫)‪void MyMethod(int[] param1, int param2‬‬


‫{‬
‫‪//code here‬‬
‫}‬

‫به پارامترهای متد باال توجه کنید‪ ،‬پارامتر اول (‪ )param1‬آرگومانی از جنس آرایه قبول میکند ولی پارامتر دوم (‪ )param2‬یک عدد صحیح‪ .‬حال اگر پارامتر‬
‫دوم (‪ )param2‬هم آرایه قبول میکرد باید برای آن هم از کروشه استفاده میکردیم‪:‬‬

‫)‪void MyMethod(int[] param1, int[] param2‬‬


‫{‬
‫‪//code here‬‬
‫}‬

‫کلمه کلیدی ‪params‬‬

‫کلمه کلیدی ‪ params‬امکان ارسال تعداد دلخواه پارامترهای همنوع و ذخیره آنها در یک آرایه ساده را فراهم میآورد‪ .‬کد زیر طریقه استفاده از کلمه کلیدی‬
‫‪ params‬را نشان میدهد ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)‪static int CalculateSum(params int[] numbers‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪int total = 0‬‬
‫‪8:‬‬
‫‪9:‬‬ ‫)‪foreach (int number in numbers‬‬
‫‪10:‬‬ ‫{‬
‫‪11:‬‬ ‫;‪total += number‬‬
‫‪12:‬‬ ‫}‬
‫‪13:‬‬
‫‪14:‬‬ ‫;‪return total‬‬
‫‪15:‬‬ ‫}‬
‫‪16:‬‬
‫‪17:‬‬ ‫)(‪public static void Main‬‬

‫‪111‬‬
‫‪18:‬‬ ‫{‬
‫‪19:‬‬ ‫;))‪Console.WriteLine("1 + 2 + 3 = {0}", CalculateSum(1, 2, 3‬‬
‫‪20:‬‬
‫‪21:‬‬ ‫;))‪Console.WriteLine("1 + 2 + 3 + 4 = {0}", CalculateSum(1, 2, 3, 4‬‬
‫‪22:‬‬
‫‪23:‬‬ ‫;))‪Console.WriteLine("1 + 2 + 3 + 4 + 5 = {0}", CalculateSum(1, 2, 3, 4, 5‬‬
‫‪24:‬‬
‫‪25:‬‬ ‫}‬
‫} ‪26:‬‬

‫‪1 + 2 + 3 = 6‬‬
‫‪1 + 2 + 3 + 4 = 10‬‬
‫‪1 + 2 + 3 + 4 + 5 = 15‬‬
‫از کلمه کلیدی ‪ params‬قبل از نوع دادهای آرایه پارامتر استفاده میشود (مثال باال)‪ .‬حال متد را سه بار با تعداد مختلف آرگومانها فراخوانی میکنیم‪ .‬این‬
‫آرگومانها در داخل یک پارامتر از نوع آرایه ذخیره میشوند‪ .‬با استفاده از حلقه ‪ foreach‬این آرگومانها را جمع و به متد فراخوان برگشت داده میشود‪ .‬وقتی از‬
‫چندین پارامتر در یک متد استفاده میکنید فقط یکی از آنها باید دارای کلمه کلیدی ‪ params‬بوده و همچنین از لحاظ مکانی باید آخرین پارامتر باشد‪ .‬اگر این‬
‫پارامتر (پارامتری که دارای کلمه کلیدی ‪ params‬است) در آخر پارامترهای دیگر قرار نگیرد و یا از چندین پارامتر ‪ params‬دار استفاده کنید با خطا مواجه‬
‫میشوید‪ .‬به مثالهای اشتباه و درست زیر توجه کنید ‪:‬‬

‫‪void SomeFunction(params int[] x, params int[] y) //ERROR‬‬

‫‪void SomeFunction(params int[] x, int y, int z) //ERROR‬‬

‫‪void SomeFunction(int x, int y, params int[] z) //Correct‬‬

‫محدوده متغیر‬

‫متغیرها در سی شارپ دارای محدوده (‪ )scope‬هستند‪ .‬محدوده یک متغیر به شما میگوید که در کجای برنامه میتوان از متغیر استفاده کرد و یا متغیر قابل‬
‫دسترسی است‪ .‬به عنوان مثال متغیری که در داخل یک متد تعریف میشود فقط در داخل بدنه متد قابل دسترسی است‪ .‬میتوان دو متغیر با نام یکسان در دو متد‬
‫مختلف تعریف کرد‪ .‬برنامه زیر این ادعا را اثبات میکند ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪static void DemonstrateScope‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪int number = 5‬‬
‫‪8:‬‬
‫‪9:‬‬ ‫;)‪Console.WriteLine("number inside method DemonstrateScope() = {0}", number‬‬
‫‪10:‬‬ ‫}‬
‫‪11:‬‬
‫‪12:‬‬ ‫)(‪public static void Main‬‬
‫‪13:‬‬ ‫{‬
‫‪14:‬‬ ‫;‪int number = 10‬‬
‫‪112‬‬
‫‪15:‬‬
‫‪16:‬‬ ‫;)(‪DemonstrateScope‬‬
‫‪17:‬‬
‫‪18:‬‬ ‫;)‪Console.WriteLine("number inside the Main method = {0}", number‬‬
‫‪19:‬‬ ‫}‬
‫} ‪20:‬‬

‫‪number inside method DemonstrateScope() = 5‬‬


‫‪number inside the Main method = 10‬‬
‫مشاهده میکنید که حتی اگر ما دو متغیر با نام یکسان تعریف کنیم که دارای محدودههای متفاوتی هستند‪ ،‬میتوان به هر کدام از آنها مقادیر مختلفی‬
‫اختصاص داد‪ .‬متغیر تعریف شده در داخل متد )(‪ Main‬هیچ ارتباطی به متغیر داخل متد )(‪ DemonstrateScope‬ندارد‪ .‬وقتی به مبحث کالسها‬
‫رسیدیم در این باره بیشتر توضیح خواهیم داد‪.‬‬

‫پارامترهای اختیاری‬

‫پارامترهای اختیاری همانگونه که از اسمشان پیداست اختیاری هستند و می توان به آنها آرگومان ارسال کرد یا نه‪ .‬این پارامترها دارای مقادیر پیشفرضی هستند‪.‬‬
‫اگر به اینگونه پارامترها آرگومانی ارسال نشود از مقادیر پیشفرض استفاده میکنند‪ .‬به مثال زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)"!‪static void PrintMessage(string message = "Welcome to Visual C# Tutorials‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;)‪Console.WriteLine(message‬‬
‫‪8:‬‬ ‫}‬
‫‪9:‬‬
‫‪10:‬‬ ‫)(‪public static void Main‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫;)(‪PrintMessage‬‬
‫‪13:‬‬
‫‪14:‬‬ ‫;)"!‪PrintMessage("Learn C# Today‬‬
‫‪15:‬‬ ‫}‬
‫} ‪16:‬‬

‫!‪Welcome to Visual C# Tutorials‬‬


‫!‪Learn C# Today‬‬
‫متد )(‪( PrintMessage‬خطوط ‪ )5-8‬یک پارامتر اختیاری دارد‪ .‬برای تعریف یک پارامتر اختیاری میتوان به آسانی و با استفاده از عالمت = یک مقدار را به‬
‫یک پارامتر اختصاص داد (مثال باال خط ‪ .)5‬دو بار متد را فراخوانی میکنیم‪ .‬در اولین فراخوانی (خط ‪ )12‬ما آرگومانی به متد ارسال نمیکنیم بنابراین متد از مقدار‬
‫پیشفرض (!‪ )Welcome to Visual C# Tutorials‬استفاده میکند‪ .‬در دومین فراخوانی (خط ‪ )14‬یک پیغام (آرگومان) به متد ارسال میکنیم که‬
‫جایگزین مقدار پیشفرض پارامتر میشود‪ .‬اگر از چندین پارامتر در متد استفاده میکنید همه پارامترهای اختیاری باید در آخر بقیه پارامترها ذکر شوند‪.‬‬
‫به مثالهای زیر توجه کنید‪.‬‬

‫‪113‬‬
‫‪void SomeMethod(int opt1 = 10, int opt2 = 20, int req1, int req2) //ERROR‬‬

‫‪void SomeMethod(int req1, int opt1 = 10, int req2, int opt2 = 20) //ERROR‬‬

‫‪void SomeMethod(int req1, int req2, int opt1 = 10, int opt2 = 20) //Correct‬‬

‫وقتی متدهای با چندین پارامتر اختیاری فراخوانی میشوند باید به پارامترهایی که از لحاظ مکانی در آخر بقیه پارامترها نیستند مقدار اختصاص داد‪ .‬به یاد داشته‬
‫باشید که نمیتوان برای نادیده گرفتن یک پارامتر به صورت زیر عمل کرد ‪:‬‬

‫)‪void SomeMethod(int required1, int optional1 = 10, int optional2 = 20‬‬


‫{‬
‫‪//Some Code‬‬
‫}‬

‫‪// ... Code omitted for demonstration‬‬

‫‪SomeMethod(10, , 100); //Error‬‬

‫اگر بخواهید از یک پارامتر اختیاری که در آخر پارامترهای دیگر نیست رد شوید و آن را نادیده بگیرید باید به از نام پارامترها استفاده کنید‪.‬‬

‫;)‪SomeMethod(10, optional2: 100‬‬

‫برای استفاده از نام آرگومانها شما به راحتی میتوانید نام مخصوص پارامتر و بعد از نام عالمت کالن ( ‪ ) :‬و بعد مقدار اختصاص شده به آن را نوشت مانند‬
‫(‪ . )optional2: 100‬متد باال هیچ آرگومانی برای پارامتر اختیاری ‪ optional1‬ندارد بنابراین این پارامتر از مقدار پیشفرضی که در زمان تعریف متد به‬
‫آن اختصاص داده شده است استفاده میکند‪.‬‬

‫سربارگذاری متدها‬

‫سربارگذاری متدها به شما اجازه میدهد که دو متد با نام یکسان تعریف کنید که دارای امضاء و تعداد پارامترهای مختلف هستند‪ .‬برنامه از روی آرگومانهایی که‬
‫شما به متد ارسال میکنید به صورت خودکار تشخیص میدهد که کدام متد را فراخوانی کردهاید یا کدام متد مد نظر شماست‪ .‬امضای یک متد نشان دهنده‬
‫ترتیب و نوع پارامترهای آن است‪ .‬به مثال زیر توجه کنید ‪:‬‬

‫)‪void MyMethod(int x, double y, string z‬‬

‫که امضای متد باال‬

‫)‪MyMethod(int, double, string‬‬

‫به این نکته توجه کنید که نوع برگشتی و نام پارامترها شامل امضای متد نمیشوند‪ .‬در مثال زیر نمونهای از سربارگذاری متدها آمده است‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)‪static void ShowMessage(double number‬‬
‫‪6:‬‬ ‫{‬

‫‪114‬‬
‫‪7:‬‬ ‫;)"‪Console.WriteLine("Double version of the method was called.‬‬
‫‪8:‬‬ ‫}‬
‫‪9:‬‬
‫‪10:‬‬ ‫)‪static void ShowMessage(int number‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫;)"‪Console.WriteLine("Integer version of the method was called.‬‬
‫‪13:‬‬ ‫}‬
‫‪14:‬‬
‫‪15:‬‬ ‫)(‪static void Main‬‬
‫‪16:‬‬ ‫{‬
‫‪17:‬‬ ‫;)‪ShowMessage(9.99‬‬
‫‪18:‬‬ ‫;)‪ShowMessage(9‬‬
‫‪19:‬‬ ‫}‬
‫} ‪20:‬‬

‫‪Double version of the method was called.‬‬


‫‪Integer version of the method was called.‬‬
‫در برنامه باال دو متد با نام مشابه تعریف شدهاند‪ .‬اگر سربارگذاری متد توسط سی شارپ پشتیبانی نمیشد برنامه زمان زیادی برای انتخاب یک متد از بین‬
‫متدهایی که فراخوانی میشوند الزم داشت‪ .‬رازی در نوع پارامترهای متد نهفته است‪ .‬کامپایلر بین دو یا چند متد همنام در صورتی فرق میگذارد که پارامترهای‬
‫متفاوتی داشته باشند‪ .‬وقتی یک متد را فراخوانی میکنیم‪ ،‬متد نوع آرگومانها را تشخیص میدهد‪.‬‬
‫در فراخوانی اول (خط ‪ )19‬ما یک مقدار ‪ double‬را به متد)(‪ ShowMessage‬ارسال کردهایم در نتیجه متد )(‪( ShowMessage‬خطوط ‪ )7-10‬که‬
‫دارای پارامتری از نوع ‪ double‬اجرا میشود‪ .‬در بار دوم که متد فراخوانی میشود (خط ‪ )20‬ما یک مقدار ‪ int‬را به متد )(‪ ShowMessage‬ارسال میکنیم‬
‫متد )(‪( ShowMessage‬خطوط ‪ )12-15‬که دارای پارامتری از نوع ‪ int‬است اجرا میشود‪ .‬معنای اصلی سربارگذاری متد همین است که توضیح داده شد‪.‬‬
‫هدف اصلی از سربارگذاری متدها این است که بتوان چندین متد که وظیفه یکسانی انجام میدهند را تعریف کرد تعداد زیادی از متدها در کالسهای دات نت‬
‫سربارگذاری میشوند مانند متد )(‪ WriteLine‬از کالس ‪ .Console‬قبالً مشاهده کردید که این متد میتواند یک آرگومان از نوع رشته دریافت کند و آن را‬
‫نمایش دهد‪ ،‬و در حالت دیگر میتواند دو یا چند آرگومان قبول کند‪.‬‬

‫بازگشت (‪)Recursion‬‬

‫بازگشت فرایندی است که در آن متد مدام خود را فراخوانی میکند تا زمانی که به یک مقدار مورد نظر برسد‪ .‬بازگشت یک مبحث پیچیده در برنامه نویسی است‬
‫و تسلط به آ ن کار راحتی نیست‪ .‬به این نکته هم توجه کنید که بازگشت باید در یک نقطه متوقف شود وگرنه برای بی نهایت بار‪ ،‬متد‪ ،‬خود را فراخوانی میکند‪ .‬در‬
‫این درس یک مثال ساده از بازگشت را برای شما توضیح میدهیم‪ .‬فاکتوریل یک عدد صحیح مثبت )!‪(n‬شامل حاصل ضرب همه اعداد مثبت صحیح کوچکتر‬
‫یا مساوی آن میباشد‪ .‬به فاکتوریل عدد ‪ 5‬توجه کنید‪.‬‬

‫‪5! = 5 * 4 * 3 * 2 * 1 = 120‬‬

‫بنابراین برای ساخت یک متد بازگشتی باید به فکر توقف آن هم باشیم‪ .‬بر اساس توضیح بازگشت‪ ،‬فاکتوریل فقط برای اعداد مثبت صحیح است‪ .‬کوچکترین‬
‫عدد صحیح مثبت ‪ 1‬است‪ .‬در نتیجه از این مقدار برای متوقف کردن بازگشت استفاده میکنیم‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)‪static long Factorial(int number‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫)‪if (number == 1‬‬
‫‪8:‬‬ ‫;‪return 1‬‬

‫‪115‬‬
‫‪9:‬‬
‫‪10:‬‬ ‫;)‪return number * Factorial(number - 1‬‬
‫‪11:‬‬ ‫}‬
‫‪12:‬‬
‫‪13:‬‬ ‫)(‪public static void Main‬‬
‫‪14:‬‬ ‫{‬
‫‪15:‬‬ ‫;))‪Console.WriteLine(Factorial(5‬‬
‫‪16:‬‬ ‫}‬
‫} ‪17:‬‬

‫‪120‬‬
‫متد مقدار بزرگی را بر میگرداند چون محاسبه فاکتوریل میتواند خیلی بزرگ باشد‪ .‬متد یک آرگومان که یک عدد است و میتواند در محاسبه مورد استفاده قرار‬
‫گیرد را میپذیرد‪ .‬در داخل متد یک دستور ‪ if‬مینویسیم و در خط ‪ 7‬می گوییم که اگر آرگومان ارسال شده برابر ‪ 1‬باشد سپس مقدار ‪ 1‬را برگردان در غیر‬
‫اینصورت به خط بعد برو‪ .‬این شرط باعث توقف تکرارها نیز میشود‪.‬‬
‫در خط ‪ 10‬مقدار جاری متغیر ‪ number‬در عددی یک واحد کمتر از خودش (‪ )number – 1‬ضرب میشود‪ .‬در این خط متد ‪ Factorial‬خود را فراخوانی‬
‫میکند و آرگومان آن در این خط همان ‪ number – 1‬است‪ .‬مثالً اگر مقدار جاری ‪ number 10‬باشد یعنی اگر ما بخواهیم فاکتوریل عدد ‪ 10‬را به دست‬
‫بیاوریم آرگومان متد ‪ Factorial‬در اولین ضرب ‪ 9‬خواهد بود‪ .‬فرایند ضرب تا زمانی ادامه مییابد که آرگومان ارسال شده با عدد ‪ 1‬برابر نشود‪ .‬شکل زیر‬
‫فاکتوریل عدد ‪ 5‬را نشان میدهد‪.‬‬

‫کد باال را به وسیله یک حلقه ‪ for‬نیز میتوان نوشت‪.‬‬

‫;‪factorial = 1‬‬

‫) ‪for ( int counter = number; counter >= 1; counter--‬‬


‫;‪factorial *= counter‬‬

‫این کد از کد معادل بازگشتی آن آسانتر است‪ .‬از بازگشت در زمینههای خاصی در علوم کامپیوتر استفاده میشود‪ .‬استفاده از بازگشت حافظه زیادی اشغال میکند‬
‫پس اگر سرعت برای شما مهم است از آن استفاده نکنید‪.‬‬

‫‪116‬‬
)Delegates(‫نماینده ها‬

‫ برای تعریف یک‬.‫ همچنین میتوانند رفتار هر متدی را کپی برداری کنند‬.‫ ها انواعی هستند که مرجع یک متد را در خود ذخیره میکنند‬delegate
‫ بسیار شبیه به تعریف یک متد است با این تفاوت که متد بدنه دارد ولی‬delegate ‫ تعریف یک‬.‫ استفاده میشود‬delegate ‫از کلمه کلیدی‬delegate
‫ ها می گویند که چه نوع متدی را میتوانند‬delegate .‫ دقیق ًا مانند متدها دارای نوع برگشتی و مجموعهای از پارامترها هستند‬delegate .‫ ندارد‬delegate
‫ ها را میتوان به عنوان یک ظرف در نظر گرفت که میتوانید هر تعداد متد را که دوست دارید را در داخل آن قرار‬delegate ‫ به زبان ساده‬.‫در خود ذخیره کنند‬
: ‫ نشان داده شده است‬delegate ‫ در زیر نحوه تعریف‬.‫ را فراخوانی میکنید تک به تک متدهای داخل آن اجرا میشوند‬delegate ‫ زمانی که شما‬.‫دهید‬

delegate returnType DelegateName(dt param1, dt param2, ... dt paramN);

: ‫ و فواید آن نشان داده شده است‬delegate ‫در زیر نحوه استفاده از یک‬

1: using System;
2:
3: public class Program
4: {
5: delegate void ArithmeticDelegate(int num1, int num2);
6:
7: static void Add(int x, int y)
8: {
9: Console.WriteLine("Sum is {0}.", x + y);
10: }
11:
12: static void Subtract(int x, int y)
13: {
14: Console.WriteLine("Difference is {0}.", x - y);
15: }
16:
17: static void Main()
18: {
19: ArithmeticDelegate Operation;
20:
21: int num1, num2;
22:
23: Console.Write("Enter first number: ");
24: num1 = Convert.ToInt32(Console.ReadLine());
25:
26: Console.Write("Enter second number: ");
27: num2 = Convert.ToInt32(Console.ReadLine());
28:
29: if (num1 < num2)
30: {
31: Operation = new ArithmeticDelegate(Add);
32: }
33: else
34: {
35: Operation = new ArithmeticDelegate(Subtract);
36: }
37:
117
‫‪38:‬‬ ‫;)‪Operation(num1, num2‬‬
‫‪39:‬‬ ‫}‬
‫} ‪40:‬‬

‫‪Enter first number: 3‬‬


‫‪Enter second number: 5‬‬
‫‪Sum is 8‬‬
‫‪Enter first number: 5‬‬
‫‪Enter second number: 3‬‬
‫‪Difference is 2‬‬
‫در خط ‪ 5‬یک نماینده تعریف شده است‪ .‬از کلمه کلیدی ‪ delegate‬برای نشان داده آن استفاده شده است‪ .‬به دنبال آن نوع برگشتی متدی که قبول میکند هم‬
‫آمده است‪ .‬برای نامگذاری ‪ delegate‬مانند متدها از روش ‪ Pascal‬استفاده میکنیم‪ .‬همچنین برای تشخیص بهتر آنها بهتر است از کلمه ‪ delegate‬در‬
‫نامگذاری آنها استفاده شود‪.‬‬
‫پارامترهایی که برای ‪ delegate‬تعریف میکنیم باید از نظر نوع و تعداد با پارامترهای متدها برابر باشد‪ delegate .‬ی که در خط ‪ 5‬تعریف شده است فقط‬
‫مرجع متدهایی را قبول میکند دارای مقدار برگشتی نیستند و دو پارامتر از نوع ‪ int‬دارند‪ .‬بعد از تعریف ‪ delegate‬دو متد با امضای دقیقاً مشابه با امضای‬
‫‪ delegate‬تعریف میکنیم ‪.‬‬
‫هر دو متد هیچ مقداربرگشتی ندارند و هر دو‪ 2 ،‬آرگومان از نوع ‪ int‬قبول میکنند‪ .‬در داخل متد ‪ Main‬یک متغیر از نوع ‪ delegate‬ی که قبالً تعریف‬
‫کردهایم‪ ،‬تعریف میکنیم (خط ‪ .)19‬این متغیر اشاره به متدی دارد که امضای آن با امضای ‪ delegate‬مطابقت دارد‪ .‬برنامه از کاربر میخواهد دو مقدار از نوع‬
‫‪ int‬را وارد کند‪.‬‬
‫بعد از وارد کردن مقادیر وارد اولین دستور ‪ if‬میشویم‪ ،‬چنانچه مقدار اولین عددی که کاربر وارد کرده از دومین عدد وارد شده کمتر باشد‪ ،‬دو عدد با هم جمع‬
‫می شوند‪ .‬در غیر اینصورت اگر مقدار اولین عدد بزرگتر یا مساوی دومین عدد باشد از هم کم میشوند‪ .‬برای ارجاع یک متد به یک ‪ delegate‬به صورت زیر‬
‫عمل میکنیم ‪:‬‬

‫;)‪variable = new DelegateName(MethodName‬‬

‫وقتی یک ‪ delegate‬را با یک مرجع متد برابر قرار میدهیم باید قبل از نام ‪ delegate‬از کلمه کلیدی ‪ new‬استفاده کنیم (مثال باال)‪ .‬در داخل پرانتز نام‬
‫متدی که ‪ delegate‬به آن مراجعه میکند نشان داده شده است‪ .‬یک راه بسیار سادهتر برابر قرار دادن نام متد با متغیر ‪ delegate‬است ‪:‬‬

‫;‪Operation = Add‬‬
‫;‪Operation = Subtract‬‬

‫به دستور ‪ if‬بر میگردیم وقتی شرط درست باشد‪ delegate ،‬را به متد )(‪ add‬و هنگامی که شرط نادرست باشد آن را به متد )(‪ Subtract‬ارجاع میدهیم‪.‬‬
‫اجرای ‪ delegate‬باعث اجرای متدی میشود که ‪ delegate‬به آن مراجعه میکند‪ .‬اگر قصد داشته باشید که بیش از یک متد را به ‪ delegate‬اضافه کنید‬
‫باید از عملگر =‪ +‬استفاده نمایید ‪:‬‬

‫;‪MyDelegate del = Method1‬‬


‫;‪del += Method2‬‬
‫;‪del += Method3‬‬
‫‪...‬‬

‫کاربرد اصلی ‪ delegate‬ها هنگام کار با رویدادها میباشد که در درسهای آینده توضیح میدهیم‪.‬‬

‫آرگومان های خط فرمان (‪)Command Line Arguments‬‬

‫‪118‬‬
‫برای اجرای موفق یک برنامه سی شارپی باید یک متد مهم به نام متد ()‪ Main‬وجود داشته باشد که نقطه آغاز برنامه است‪ .‬این متد باید به صورت ‪public‬‬
‫‪ static‬تعریف شود‪ .‬همه ما می دانیم که برای متدها میتوان آرگومان ارسال کرد‪ ،‬اما برای متد ‪ )Main(string[] args‬چطور؟ جواب مثبت است‪ .‬شما‬
‫میتوانید از طریق دستور خط فرمان ویندوز یا همان ‪ CMD‬آرگومانهایی را برای این متد ارسال کنید‪ .‬برای روشن شدن مطلب یک برنامه کنسول به نام‬
‫‪ Sample‬ایجاد کنید‪ ،‬سپس کدهای برنامه را به صورت زیر بنویسید ‪:‬‬

‫;‪using System‬‬

‫‪namespace Sample‬‬
‫{‬
‫‪class Program‬‬
‫{‬
‫)‪public static void Main(string[] args‬‬
‫{‬
‫;)]‪Console.WriteLine("First Name is " + args[0‬‬
‫‪Console.WriteLine("Last‬‬ ‫;)]‪Name is " + args[1‬‬
‫;)(‪Console.ReadLine‬‬
‫}‬
‫}‬
‫}‬

‫برنامه را یک بار اجرا و ذخیره کنید (ممکن است با پیغام خطا مواجه شوید ولی مهم نیست)‪ .‬به پارامتر ‪ args‬توجه کنید‪ .‬در حقیقت این پارامتر یک آرایه رشتهای‬
‫است که میتواند چندین آرگومان از نوع رشته قبول کند‪ .‬اگر برنامهتان را ایجاد کرده و به فایل با پسوند ‪ .exe‬دسترسی داشته باشید میتوانید پارامترهای‬
‫رشتهای را به متد ()‪ Main‬ارسال کنید‪ .‬فایل ‪ Sample.exe‬را که در پوشه ‪ Debug‬برنامهتان است را به یک درایو یا پوشه مشخص که مسیر گیج کنندهای‬
‫نداشته باشد انتقال دهید‪ .‬در این مثال ما فایل ‪ Sample.exe‬را مستقیماً در درایو ‪ C‬قرار میدهیم‪ .‬حال ‪ CMD‬ویندوز را اجرا کنید‪ ،‬سپس کدهای زیر‬
‫(خطوط قرمز) را در داخل ‪ CMD‬نوشته و دکمه ‪ Enter‬را بزنید ‪:‬‬

‫]‪Microsoft Windows[Version 6.1.7601‬‬


‫‪Copyright(c) 2009 Microsoft Corporation.All rights reserved.‬‬

‫‪C:\Users\VisualCsharp>cd/‬‬

‫‪C:\>Sample Steven Clark‬‬


‫‪First Name is Steven‬‬
‫‪Last‬‬ ‫‪Name is Clark‬‬
‫با نوشتن نام فایل‪ ،‬باعث اجرای آن میشویم‪ .‬بعد از نوشتن نام فایل کلمه ‪ Steven‬و سپس عدد ‪ Clark‬را مینویسیم‪ .‬همانطور که در کد مشاهده میکنید ما‬
‫دو متغیر به نامهای ‪ ]args[0‬و ‪ ]args[1‬تعریف کردهایم‪ .‬این دو متغیر به ترتیب خانههای اول و دوم آرایه هستند‪ .‬کلمه ‪ Steven‬در متغیر رشتهای‬
‫‪ ]args[0‬که اولین عنصر آرایه و کلمه ‪ Clark‬را در متغیر رشتهای ‪ ]args[1‬که دومین عنصر آرایه است ذخیره و سپس با استفاده از متد ()‪WriteLine‬‬
‫آنها را چاپ میکنیم‪ .‬در حقیقت بسیاری از برنامهها از این تکنیک استفاده میکنند‪ .‬شما میتوانید با ارسال آرگومانهایی به متد ()‪ Main‬نحوه اجرای برنامه را‬
‫تغییر دهید‪.‬‬

‫شمارش (‪)Enumeration‬‬

‫‪119‬‬
‫‪ Enumeration‬یا شمارش راهی برای تعریف دادههایی است که میتوانند مقادیر محدودی که شما از قبل تعریف کردهاید را بپذیرند‪ .‬به عنوان مثال شما‬
‫میخواهید یک متغیر تعریف کنید که فقط مقادیر جهت (جغرافیایی) مانند ‪ north ،west ،east‬و ‪ south‬را در خود ذخیره کند‪ .‬ابتدا یک ‪enumeration‬‬
‫تعریف میکنید و برای آن یک اسم انتخاب کرده و بعد از آن تمام مقادیر ممکن که میتوانند در داخل بدنه آن قرار بگیرند تعریف میکنید‪ .‬به نحوه تعریف یک‬
‫‪ enumeration‬توجه کنید‪:‬‬

‫‪enum enumName‬‬
‫{‬
‫‪value1,‬‬
‫‪value2,‬‬
‫‪value3,‬‬
‫‪.‬‬
‫‪.‬‬
‫‪.‬‬
‫‪valueN‬‬
‫}‬

‫ابتدا کلمه کلیدی ‪ enum‬و سپس نام آن را به کار میبریم‪ .‬در سی شارپ برای نامگذاری ‪ enumeration‬از روش پاسکال استفاده کنید‪ .‬در بدنه ‪enum‬‬
‫مقادیری وجود دارند که برای هر کدام یک نام در نظر گرفته شده است‪ .‬به یک مثال توجه کنید ‪:‬‬

‫‪enum Direction‬‬
‫{‬
‫‪North,‬‬
‫‪East,‬‬
‫‪South,‬‬
‫‪West‬‬
‫}‬

‫در حالت پیشفرض مقادیری که یک ‪ enumeration‬میتواند ذخیره کند از نوع ‪ int‬هستند‪ .‬به عنوان مثال مقدار پیشفرض ‪ north‬صفر و مقدار بقیه مقادیر‬
‫یک واحد بیشتر از مقدار قبلی خودشان است‪ .‬بنابراین مقدار ‪ east‬برابر ‪ ،1‬مقدار ‪ south‬برابر ‪ 2‬و مقدار ‪ west‬برابر ‪ 3‬است‪ .‬میتوانید این مقادیر پیشفرض را به‬
‫دلخواه تغییر دهید‪ ،‬مانند‪:‬‬

‫‪enum Direction‬‬
‫{‬
‫‪North = 3,‬‬
‫‪East = 5,‬‬
‫‪South = 7,‬‬
‫‪West = 9‬‬
‫}‬

‫اگر به عنوان مثال هیچ مقداری به یک عنصر اختصاص ندهید آن عنصر به صورت خودکار مقدار می کیرد‪.‬‬

‫‪enum Direction‬‬
‫{‬
‫‪North = 3,‬‬
‫‪East = 5,‬‬
‫‪South,‬‬
‫‪West‬‬
‫}‬

‫‪120‬‬
‫در مثال باال مشاهده میکنید که ما هیچ مقداری به ‪ south‬در نظر نگرفتهایم بنابر این به صورت خودکار یک واحد بیشتر از ‪ east‬یعنی ‪ 6‬و به ‪ west‬یک واحد‬
‫بیشتر از ‪ south‬یعنی ‪ 7‬اختصاص داده میشود‪ .‬همچنین میتوان مقادیر یکسانی برای عناصر ‪ enumeration‬در نظر گرفت‪ .‬مثال ‪:‬‬

‫‪enum Direction‬‬
‫{‬
‫‪North = 3,‬‬
‫‪East,‬‬
‫‪South = North,‬‬
‫‪West‬‬
‫}‬

‫میتوانید مقادیر باال را حدس بزنید؟ مقادیر ‪ west ،south ،east ،north‬به ترتیب ‪ 4 ،3 ،4 ،3‬است‪ .‬وقتی مقدار ‪ 3‬را به ‪ north‬میدهیم مقدار ‪ east‬برابر ‪4‬‬
‫میشود‪ .‬سپس وقتی مقدار ‪south‬را برابر ‪ 3‬قرار دهیم به صورت اتوماتیک مقدار ‪ west‬برابر ‪ 4‬میشود‪ .‬اگر نمیخواهید که مقادیر آیتمهای ‪enumeration‬‬
‫شما پیشفرض (از نوع ‪ )int‬باشد میتوانید از نوع مثالً ‪ byte‬به عنوان نوع دادهای آیتمهای آن اسفاده کنید‪.‬‬

‫‪enum Direction : byte‬‬


‫{‬
‫‪North,‬‬
‫‪East,‬‬
‫‪South,‬‬
‫‪West‬‬
‫}‬

‫نوع دادهای ‪ byte‬فقط شامل مقادیر بین ‪ 0‬تا ‪ 255‬میشود بنابر این تعداد مقادیر که شما میتوانید به ‪ enumeration‬اضافه کنید محدود میباشد‪ .‬به نحوه‬
‫استفاده از ‪ enumeration‬در یک برنامه سی شارپ توجه کنید‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: enum Direction‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫‪North = 1,‬‬
‫‪6:‬‬ ‫‪East,‬‬
‫‪7:‬‬ ‫‪South,‬‬
‫‪8:‬‬ ‫‪West‬‬
‫} ‪9:‬‬
‫‪10:‬‬
‫‪11: public class Program‬‬
‫{ ‪12:‬‬
‫‪13:‬‬ ‫)(‪public static void Main‬‬
‫‪14:‬‬ ‫{‬
‫‪15:‬‬ ‫;‪Direction myDirection‬‬
‫‪16:‬‬
‫‪17:‬‬ ‫;‪myDirection = Direction.North‬‬
‫‪18:‬‬
‫‪19:‬‬ ‫;))(‪Console.WriteLine("Direction: {0}", myDirection.ToString‬‬
‫‪20:‬‬ ‫}‬
‫} ‪21:‬‬

‫‪Direction: North‬‬

‫‪121‬‬
‫ابتدا ‪ enumeration‬را در خطوط ‪ 3-9‬تعریف میکنیم‪ .‬توجه کنید که ‪ enumeration‬را خارج از کالس قرار دادهایم‪ .‬این کار باعث میشود که‬
‫‪ enumeration‬در سراسر برنامه در دسترس باشد‪ .‬میتوان ‪ enumeration‬را در داخل کالس هم تعریف کرد ولی در این صورت فقط در داخل کالس‬
‫قابل دسترس است‪.‬‬

‫‪class Program‬‬
‫{‬
‫‪enum Direction‬‬
‫{‬
‫‪//Code omitted‬‬
‫}‬

‫)‪static void Main(string[] args‬‬


‫{‬
‫‪//Code omitted‬‬
‫}‬
‫}‬

‫برنامه را ادامه میدهیم‪ .‬در داخل بدنه ‪ enumeration‬نام چهار جهت جغرافیایی وجود دارد که هر یک از آنها با ‪ 1‬تا ‪ 4‬مقدار دهی شدهاند‪ .‬در خط ‪ 15‬یک‬
‫متغیر تعریف شده است که مقدار یک جهت را در خود ذخیره میکند‪ .‬نحوه تعریف آن به صورت زیر است ‪:‬‬

‫;‪enumType variableName‬‬

‫در اینجا ‪ enumType‬نوع داده شمارشی (مثالً ‪ Direction‬یا مسیر) میباشد و ‪ variableName‬نیز نامی است که برای آن انتخاب کردهایم که در مثال‬
‫قبل ‪ myDirection‬است‪ .‬سپس یک مقدار به متغیر ‪ myDirection‬اختصاص میدهیم (خط ‪ .)17‬برای اختصاص یک مقدار به صورت زیر عمل میکنیم‬
‫‪:‬‬

‫;‪variable = enumType.value‬‬

‫ابتدا نوع ‪ Enumeration‬سپس عالمت نقطه و بعد مقدار آن (مثالً ‪ )North‬را مینویسیم‪ .‬میتوان یک متغیر را فوراً‪ ،‬به روش زیر مقدار دهی کرد ‪:‬‬

‫;‪Direction myDirection = Direction.North‬‬

‫حال در خط ‪ 19‬با استفاده از )(‪ Console.WriteLine‬مقدار ‪ myDirection‬را چاپ میکنیم‪ .‬توجه کنید که با استفاده از متد )(‪ ToString‬مقدار‬
‫عددی ‪ myDirection‬را به رشته‪ ،‬جهت چاپ تبدیل میکنیم‪.‬‬
‫تصور کنید که اگر ‪ enumeration‬نبود شما مجبور بودید که به جای کلمات اعداد را حفظ کنید چون مقادیر ‪ enumeration‬در واقع اعدادی هستند که با‬
‫نام مستعار توسط شما یا هر کس دیگر تعریف میشوند‪ .‬متغیرهای شمارشی میتوانند به انواع دیگری مانند ‪ int‬یا ‪ string‬تبدیل شوند‪ .‬همچنین یک مقدار‬
‫رشتهای میتواند به نوع شمارشی معادلش تبدیل شود‪.‬‬

‫تبدیل انواع شمارشی‬

‫می توان انواع شمارشی را به دیگر مقادیر تبدیل کرد و بالعکس‪ .‬مقادیر شمارشی در واقع مقادیر عددی هستند که برای درک بهتر آنها‪ ،‬به هر عدد یک نام‬
‫اختصاص داده شده است‪ .‬به مثال زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: enum Direction‬‬

‫‪122‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫‪North,‬‬
‫‪6:‬‬ ‫‪East,‬‬
‫‪7:‬‬ ‫‪South,‬‬
‫‪8:‬‬ ‫‪West‬‬
‫} ‪9:‬‬
‫‪10: public class Program‬‬
‫{ ‪11:‬‬
‫‪12:‬‬ ‫)(‪public static void Main‬‬
‫‪13:‬‬ ‫{‬
‫‪14:‬‬ ‫;‪Direction myDirection = Direction.East‬‬
‫‪15:‬‬ ‫;‪int myDirectionCode = (int)myDirection‬‬
‫‪16:‬‬
‫‪17:‬‬ ‫;)‪Console.WriteLine("Value of East is {0}", myDirectionCode‬‬
‫‪18:‬‬
‫‪19:‬‬ ‫;‪myDirection = (Direction)3‬‬
‫‪20:‬‬ ‫;))(‪Console.WriteLine("nDirection: {0}", myDirection.ToString‬‬
‫‪21:‬‬ ‫}‬
‫} ‪22:‬‬

‫‪Value of East is 1‬‬

‫‪Direction: West‬‬
‫در خط ‪ 14‬متغیر ‪ myDirection‬را به مقدار ‪ East‬نوع شمارشی ‪ Direction‬اختصاص دادهایم‪ .‬در حالت پیشفرض مقدار ‪ East‬در داخل آیتمهای این داده‬
‫شمارشی ‪ 1‬میباشد‪ .‬در خط ‪ 15‬نشان نحوه تبدیل یک آیتم از نوع شمارشی به عدد صحیح معادل آن به روش تبدیل صریح نشان داده شده است‪ .‬نحوه این‬
‫تبدیل به صورت زیر است‪:‬‬

‫;‪variable = (DestinationDataType)enumerationVariable‬‬

‫از آنجاییکه متغیر ‪( myDirectionCode‬خط ‪ )15‬از نوع ‪ int‬است در نتیجه یک مقدار ‪ int‬باید در آن قرار بگیرد‪ .‬میتوان به سادگی نوع داده مقصد را در‬
‫داخل یک جفت پرانتز قرار داد و آن را کنار نوع شمارشی بگذارید (خط ‪ .)15‬نتیجه یک مقدار تبدیل شده را برگشت میدهد‪ .‬در خط ‪ 19‬معکوس این کار را انجام‬
‫میدهیم‪ .‬در این خط یک مقدار صحیح را به یک مقدار شمارشی تبدیل میکنیم‪ .‬مقدار ‪ 3‬را برابر آیتم ‪ West‬قرار میدهیم‪.‬‬
‫برای تبدیل آن از روشی شبیه به تبدیل یک نوع شمارشی به صحیح استفاده میکنیم (تبدیل صریح)‪ .‬به این نکته توجه کنید که اگر عددی را که میخواهید‬
‫تبدیل کنید در محدوده انواع شمارشی نباشد‪ ،‬تبدیل انجام میشود ولی آن آیتم شمارشی و عدد برابر هم نیستند‪ .‬به عنوان مثال ‪:‬‬

‫;‪myDirection = (Direction)10‬‬

‫;))(‪Console.WriteLine("Direction: {0}", myDirection.ToString‬‬

‫‪Direction: 10‬‬
‫از آنجاییکه عدد ‪ 10‬مقدار هیچ کدام از آیتمهای نوع شمارشی مثال باال نیست (مقدار آیتمهای نوع شمارشی مثال باال به ترتیب ‪ 0‬و ‪ 1‬و ‪ 2‬و ‪ 3‬میباشد) خروجی‬
‫‪ Console‬خود عدد را نشان میدهد ولی اگر به جای عدد ‪ 10‬هر کدام از مقادیر عددی ذکر شده را قرار دهید آیتم معادل با آن نمایش داده خواهد شد‪.‬‬

‫تبدیل یک نوع رشتهای به یک نوع شمارشی‬

‫میتوان یک نوع رشتهای را به نوع شمارشی تبدیل کرد‪ .‬مثالً میخواهید رشته ”‪ “West‬را به نوع شمارشی ‪ Direction.West‬مثال باال تبدیل کنید‪ .‬برای‬
‫این کار باید از کالس ‪ Enum‬و فضای نام ‪ System‬به صورت زیر استفاده کنید ‪:‬‬

‫‪123‬‬
‫;)"‪Direction myDirection = (Direction)Enum.Parse(typeof(Direction), "West‬‬

‫;))(‪Console.WriteLine("Direction: {0}", myDirection.ToString‬‬

‫‪Direction: West‬‬
‫متد )(‪ Enum.Parse‬دارای دو پارامتر است‪ .‬اولین پارامتر نوع شمارشی است‪ .‬با استفاده از عملگر ‪ typeof‬نوع شمارشی را برگشت میدهیم‪ .‬دومین پارامتر‪،‬‬
‫رشتهای است که قرار است به نوع شمارشی تبدیل شود‪ .‬چون مقدار برگشتی از نوعشی (‪ )object‬است بنابراین یک تبدیل مناسب نوع شمارشی الزم است‪ .‬با‬
‫این جزییات االن می دانیم که چگونه یک رشته را به نوع شمارشی تبدیل کنیم‪.‬‬

‫;)‪enumType name = (enumType)Enum.Parse(typeof(enumType), string‬‬

‫اگر رشتهای که به متد ارسال میکنید جز آیتمهای داده شمارشی نباشد با خطا مواجه میشوید‪.‬‬

‫ساختار (‪)Struct‬‬

‫ساختارها یا ‪ struct‬انواع دادهای هستند که توسط کاربر تعریف میشوند (‪ )user-define‬و میتوانند دارای فیلد و متد باشند‪ .‬با ساختارها میتوان نوع دادهای‬
‫خیلی سفارشی ایجاد کرد‪ .‬فرض کنید میخواهیم داده ای ایجاد کنیم که نه تنها نام شخص را ذخیره کند بلکه سن و حقوق ماهیانه او را نیز در خود جای دهد‪.‬‬
‫برای تعریف یک ساختار به صورت زیر عمل میکنیم ‪:‬‬

‫‪struct StructName‬‬
‫{‬
‫;‪member1‬‬
‫;‪member2‬‬
‫;‪member3‬‬
‫‪...‬‬
‫;‪member4‬‬
‫}‬

‫برای تعریف ساختار از کلمه کلیدی ‪ struct‬استفاده میشود‪ .‬برای نامگذاری ساختارها از روش نامگذاری ‪ struct‬استفاده میشود‪ .‬اعضا در مثال باال‬
‫(‪ )member1-5‬میتوانند متغیر باشند یا متد‪ .‬در زیر مثالی از یک ساختار آمده است ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public struct Employee‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;‪public string name‬‬
‫‪6:‬‬ ‫;‪public int age‬‬
‫‪7:‬‬ ‫;‪public decimal salary‬‬
‫} ‪8:‬‬
‫‪9:‬‬
‫‪10: public class Program‬‬
‫{ ‪11:‬‬
‫‪12:‬‬ ‫)(‪public static void Main‬‬
‫‪13:‬‬ ‫{‬
‫‪14:‬‬ ‫;‪Employee employee1‬‬
‫‪15:‬‬ ‫;‪Employee employee2‬‬
‫‪16:‬‬

‫‪124‬‬
‫‪17:‬‬ ‫;"‪employee1.name = "Jack‬‬
‫‪18:‬‬ ‫;‪employee1.age = 21‬‬
‫‪19:‬‬ ‫;‪employee1.salary = 1000‬‬
‫‪20:‬‬
‫‪21:‬‬ ‫;"‪employee2.name = "Mark‬‬
‫‪22:‬‬ ‫;‪employee2.age = 23‬‬
‫‪23:‬‬ ‫;‪employee2.salary = 800‬‬
‫‪24:‬‬
‫‪25:‬‬ ‫;)"‪Console.WriteLine("Employee 1 Details‬‬
‫‪26:‬‬ ‫‪Console.WriteLine("Name‬‬ ‫‪: {0}",‬‬ ‫;)‪employee1.name‬‬
‫‪27:‬‬ ‫‪Console.WriteLine("Age‬‬ ‫‪: {0}",‬‬ ‫;)‪employee1.age‬‬
‫‪28:‬‬ ‫;)‪Console.WriteLine("Salary: {0:C}", employee1.salary‬‬
‫‪29:‬‬
‫‪30:‬‬ ‫‪Console.WriteLine(); //Seperator‬‬
‫‪31:‬‬
‫‪32:‬‬ ‫;)"‪Console.WriteLine("Employee 2 Details‬‬
‫‪33:‬‬ ‫‪Console.WriteLine("Name‬‬ ‫‪: {0}",‬‬ ‫;)‪employee2.name‬‬
‫‪34:‬‬ ‫‪Console.WriteLine("Age‬‬ ‫‪: {0}",‬‬ ‫;)‪employee2.age‬‬
‫‪35:‬‬ ‫;)‪Console.WriteLine("Salary: {0:C}", employee2.salary‬‬
‫‪36:‬‬ ‫}‬
‫} ‪37:‬‬

‫‪Employee 1 Details‬‬
‫‪Name‬‬ ‫‪: Jack‬‬
‫‪Age‬‬ ‫‪: 21‬‬
‫‪Salary: $1000.00‬‬

‫‪Employee 2 Datails‬‬
‫‪Name‬‬ ‫‪: Mike‬‬
‫‪Age‬‬ ‫‪: 23‬‬
‫‪Salary: $800.00‬‬
‫برای درک بهتر‪ ،‬کد باال را شرح میدهیم‪ .‬در خطوط ‪ 3-8‬یک ساختار تعریف شده است‪ .‬به کلمه ‪ Public‬در هنگام تعریف توجه کنید‪ .‬این کلمه کلیدی نشان‬
‫میدهد که ‪ Employee‬در هر جای برنامه قابل دسترسی و استفاده باشد و حتی خارج از برنامه‪ Public .‬یکی از سطوح دسترسی است که توضیحات بیشتر‬
‫در مورد آن در درسهای آینده آمده است‪ .‬قبل از نام ساختار از کلمه کلیدی ‪ struct‬استفاده میکنیم‪ .‬نام ساختار نیز از روش نامگذاری پاسکال پیروی میکند‪ .‬در‬
‫داخل بدنه ساختار سه فیلد تعریف کردهایم‪ .‬این سه فیلد مشخصات ‪( Employee‬کارمند) مان را نشان میدهند‪ .‬مثالً یک کارمند دارای نام‪ ،‬سن و حقوق‬
‫ماهانه میباشد‪ .‬همچنین هر سه فیلد به صورت ‪ Public‬تعریف شدهاند بنابراین در خارج از ساختار نیز میتوان آنها را فراخوانی کرد‪ .‬در خطوط ‪ 14‬و ‪ 15‬دو‬
‫نمونه از ساختار ‪ Employee‬تعریف شده است‪ .‬تعریف یک نمونه از ساختارها بسیار شبیه به تعریف یک متغیر معمولی است‪ .‬ابتدا نوع ساختار و سپس نام آن را‬
‫مشخص میکنید‪ .‬در خطوط ‪ 17‬تا ‪ 23‬به فیلدهای مربوط به هر ‪ Employee‬مقادیری اختصاص میدهید‪ .‬برای دسترسی به فیلدها در خارج از ساختار باید آنها‬
‫را به صورت ‪ Public‬تعریف کنید‪ .‬ابتدا نام متغیر را تایپ کرده و سپس عالمت دات (‪ ).‬و در آخر نام فیلد را مینویسیم‪.‬‬
‫وقتی که از عملگر دات استفاده میکنیم این عملگر اجازه دسترسی به اعضای مخصوص آن ساختار یا کالس را به شما میدهد‪ .‬در خطوط ‪ 25‬تا ‪ 35‬نشان داده‬
‫شده که شما چطور میتوانید به مقادیر ذخیره شده در هر فیلد ساختار دسترسی یابید‪ .‬ساختارها انواع مقداری هستند‪ .‬این بدین معنی است که اگر مثالً در مثال‬
‫باال ‪ Employee2‬را برابر ‪ Employee1‬قرار دهید‪ Employee2 ،‬همه مقادیر صفات ‪ Employee1‬را به جای اینکه به آنها مراجعه کند‪ ،‬کپی برداری‬
‫میکند‪ .‬کالس یک ساختار ساده است ولی از انواع مرجع به حساب میآید‪ .‬در مورد کالس در درسهای آینده توضیح خواهیم داد‪ .‬میتوان به ساختار‪ ،‬متد هم‬
‫اضافه کرد‪ .‬مثال زیر اصالح شده مثال قبل است‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public struct Employee‬‬
‫{ ‪4:‬‬

‫‪125‬‬
5: public string name;
6: public int age;
7: public decimal salary;
8:
9: public void SayThanks()
10: {
11: Console.WriteLine("{0} thanked you!", name);
12: }
13: }
14:
15: public class Program
16: {
17: public static void Main()
18: {
19: Employee employee1;
20: Employee employee2;
21:
22: employee1.name = "Jack";
23: employee1.age = 21;
24: employee1.salary = 1000;
25:
26: employee2.name = "Mark";
27: employee2.age = 23;
28: employee2.salary = 800;
29:
30: Console.WriteLine("Employee 1 Details");
31: Console.WriteLine("Name : {0}", employee1.name);
32: Console.WriteLine("Age : {0}", employee1.age);
33: Console.WriteLine("Salary: {0:C}", employee1.salary);
34:
35: employee1.SayThanks();
36:
37: Console.WriteLine(); //Seperator
38:
39: Console.WriteLine("Employee 2 Details");
40: Console.WriteLine("Name : {0}", employee2.name);
41: Console.WriteLine("Age : {0}", employee2.age);
42: Console.WriteLine("Salary: {0:C}", employee2.salary);
43:
44: employee2.SayThanks();
45: }
46: }

Employee 1 Details
Name : Jack
Age : 21
Salary: $1000.00
Jack thanked you!

Employee 2 Details
Name : Mike
Age : 23
Salary: $800.00

126
‫!‪Mike thanked you‬‬
‫در خطوط ‪ 9‬تا ‪ 12‬یک متد در داخل ساختار تعریف شده است‪ .‬این متد یک پیام را در صفحه نمایش نشان میدهد و مقدار فیلد ‪ name‬را گرفته و یک پیام‬
‫منحصر به فرد برای هر نمونه نشان می دهد‪ .‬برای فراخوانی متد‪ ،‬به جای اینکه بعد از عالمت دات نام فیلد را بنویسیم‪ ،‬نام متد را نوشته و بعد از آن همانطور که‬
‫در مثال باال مشاهده میکنید (خطوط ‪ 35‬و ‪ )44‬پرانتزها را قرار میدهیم و در صورتی که متد به آرگومان هم نیاز داشت در داخل پرانتز آنها را مینویسیم‪.‬‬

‫برنامه نویسی شیء گرا (‪) Object Oriented Programming‬‬

‫برنامه نویسی شیء گرا (‪ )OOP‬شام ل تعریف کالسها و ساخت اشیاء مانند ساخت اشیاء در دنیای واقعی است‪ .‬برای مثال یک ماشین را در نظر بگیرید‪.‬‬
‫این ماشین دارای خواصی مانند رنگ‪ ،‬سرعت‪ ،‬مدل‪ ،‬سازنده و برخی خواص دیگر است‪ .‬همچنین دارای رفتارها و حرکاتی مانند شتاب و پیچش به چپ و‬
‫راست و ترمز است‪ .‬اشیاء در سی شارپ تقلیدی از یک شیء مانند ماشین در دنیای واقعی هستند‪ .‬برنامه نویسی شی گرا با استفاده از کدهای دسته بندی‬
‫میکند‪.‬‬ ‫کنترل‬ ‫قابل‬ ‫بیشتر‬ ‫را‬ ‫اشیاء‬ ‫و‬ ‫کالسها‬ ‫شده‬
‫در ابتدا ما نیاز به تعریف یک کالس برای ایجاد اشیاءمان داریم‪ .‬شیء در برنامه نویسی شیءگرا از روی کالسی که شما تعریف کردهاید ایجاد میشود‪ .‬برای‬
‫مثال نقشه ساختمان شما یک کالس است که ساختمان از روی آن ساخته شده است‪ .‬کالس شامل خواص یک ساختمان مانند مساحت‪ ،‬بلندی و مواد‬
‫مورد استفاده در ساخت خانه میباشد‪ .‬در دنیای واقعی ساختمانها نیز بر اساس یک نقشه (کالس) پایه گذاری (تعریف) شدهاند‪.‬‬
‫برنامه نویسی شیء گرا یک روش جدید در برنامه نویسی است که بوسیله برنامه نویسان مورد استفاده قرار میگیرد و به آنها کمک میکند که برنامههایی با‬
‫قابلیت استفاده مجدد‪ ،‬خوانا و راحت طراحی کنند‪ .‬سی شارپ نیز یک برنامه شیء گراست و هر چیز در سی شارپ یک شیء است‪ .‬در درس زیر به شما‬
‫نحوه تعریف کالس و استفاده از اشیاء آموزش داده خواهد شد‪ .‬همچنین شما با دو مفهوم وراثت و چند ریختی که از مباحث مهم در برنامه نویسی شیء گرا‬
‫هستند در آینده آشنا میشوید‪.‬‬

‫کالس‬

‫کالس به شما اجازه میدهد یک نوع دادهای که توسط کاربر تعریف میشود و شامل فیلدها و خواص (‪ )properties‬و متدها است را ایجاد کنید‪ .‬کالس در‬
‫حکم یک نقشه برای یک شیء میباشد‪.‬‬
‫شی یک چیز واقعی است که از ساختار‪ ،‬خواص و یا رفتارهای کالس پیروی میکند‪ .‬وقتی یک شیء میسازید یعنی اینکه یک نمونه از کالس ساختهاید (در‬
‫درس ممکن است از کلمات شیء و نمونه به جای هم استفاده شود)‪.‬‬
‫ابتدا ممکن است فکر کنید که کالسها و ساختارها شبیه هم هستند‪ .‬تفاوت مهم بین این دو این است که کالسها از نوع مرجع و ساختارها از نوع دادهای هستند‪.‬‬
‫در درسهای آینده این موضوع شرح داده خواهد شد‪ .‬اگر یادتان باشد در بخشهای اولیه این آموزش کالسی به نام ‪ Program‬تعریف کردیم که شامل متد‬
‫)(‪ Main‬بود و ذکر شد که این متد نقطه آغاز هر برنامه است‪ .‬تعریف یک کالس مشابه تعریف یک ساختار است‪ .‬اما به جای استفاده از کلمه کلیدی ‪struct‬‬
‫باید از کلمه کلیدی ‪ class‬استفاده شود‪.‬‬

‫‪class ClassName‬‬
‫{‬
‫;‪field1‬‬
‫;‪field2‬‬
‫‪...‬‬
‫;‪fieldN‬‬

‫;‪method1‬‬
‫;‪method2‬‬
‫‪...‬‬
‫;‪methodN‬‬
‫‪127‬‬
}

‫ در بدنه‬.‫ استفاده میکنیم‬Pascal ‫ در نامگذاری کالسها هم از روش نامگذاری‬.‫ مینویسیم‬،‫این کلمه کلیدی را قبل از نامی که برای کالسمان انتخاب میکنیم‬
‫ فیلدها اعضای دادهای خصوصی هستند که کالس از آنها برای رفتارها و ذخیره مقادیر خاصیتهایش‬.‫کالس فیلدها و متدهای آن قرار داده میشوند‬
‫ در زیر نحوه تعریف و استفاده از یک کالس ساده به نام‬.‫ متدها رفتارها یا کارهایی هستند که یک کالس میتواند انجام دهد‬.‫) استفاده میکند‬property(
.‫ نشان داده شده است‬person

1: using System;
2:
3: public class Person
4: {
5: public string name;
6: public int age;
7: public double height;
8:
9: public void TellInformation()
10: {
11: Console.WriteLine("Name: {0}", name);
12: Console.WriteLine("Age: {0} years old", age);
13: Console.WriteLine("Height: {0}cm", height);
14: }
15: }
16:
17: public class Program
18: {
19: public static void Main()
20: {
21: Person firstPerson = new Person();
22: Person secondPerson = new Person();
23:
24: firstPerson.name = "Jack";
25: firstPerson.age = 21;
26: firstPerson.height = 160;
27: firstPerson.TellInformation();
28:
29: Console.WriteLine(); //Separator
30:
31: secondPerson.name = "Mike";
32: secondPerson.age = 23;
33: secondPerson.height = 158;
34: secondPerson.TellInformation();
35: }
36: }

Name: Jack
Age: 21 years old
Height: 160cm

Name: Mike
Age: 23 years old
Height: 158cm

128
‫برنامه باال شامل دو کالس ‪ Person‬و ‪ Program‬میباشد‪ .‬می دانیم که کالس ‪ Program‬شامل متد )(‪ Main‬است که برنامه برای اجرا به آن احتیاج‬
‫دارد ولی اجازه دهید که بر روی کالس ‪ Person‬تمرکز کنیم‪ .‬در خطوط ‪ 15-3‬کالس ‪ Person‬تعریف شده است‪ .‬در خط ‪ 3‬یک نام به کالس اختصاص‬
‫دادهایم تا به وسیله آن قابل دسترسی باشد‪ .‬همچنین سطح دسترسی آن را ‪ public‬تعریف کردهایم تا در دیگر کالسها قابل شناسایی باشد‪ .‬درباره سطوح‬
‫دسترسی در یک درس جداگانه بحث خواهیم کرد‪ .‬در داخل بدنه کالس فیلدهای آن تعریف شدهاند (خطوط ‪ .)5-7‬این سه فیلد تعریف شده خصوصیات واقعی‬
‫یک فرد در دنیای واقعی را در خود ذخیره میکنند‪ .‬یک فرد در دنیای واقعی دارای نام‪ ،‬سن‪ ،‬و قد میباشد‪ .‬در خطوط ‪ 9-14‬یک متد هم در داخل کالس به نام‬
‫)(‪ TellInformation‬تعریف شده است که رفتار کالسمان است و مثالً اگر از فرد سوالی بپرسیم در مورد خودش چیزهایی میگوید‪ .‬در داخل متد کدهایی‬
‫برای نشان دادن مقادیر موجود در فیلدها نوشته شده است‪ .‬نکتهای درباره فیلدها وجود دارد و این است که چون فیلدها در داخل کالس تعریف و به عنوان‬
‫اعضای کالس در نظر گرفته شدهاند محدوده آنها یک کالس است‪.‬‬
‫این بدین معناست که فیلدها فقط می توانند در داخل کالس یعنی جایی که به آن تعلق دارند و یا به وسیله نمونه ایجاد شده از کالس مورد استفاده قرار بگیرند‪.‬‬
‫در داخل متد )(‪ ، Main‬خطوط ‪ 21-22‬دو نمونه یا دوشی از کالس ‪ Person‬ایجاد میکنیم‪ .‬برای ایجاد یک نمونه از یک کالس باید از کلمه کلیدی ‪ new‬و‬
‫به دنبال آن نام کالس و یک جفت پرانتز قرار دهیم‪ .‬وقتی نمونه کالس ایجاد شد‪ ،‬سازنده را صدا میزنیم‪ .‬یک سازنده متد خاصی است که برای مقداردهی اولیه‬
‫به فیلدهای یک شیء به کار میرود‪ .‬وقتی هیچ آرگومانی در داخل پرانتزها قرار ندهید‪ ،‬کالس یک سازنده پیشفرض بدون پارامتر را فراخوانی میکند‪ .‬درباره‬
‫سازندهها در درسهای آینده توضیح خواهیم داد‪ .‬در خطوط ‪ 24-26‬مقادیری به فیلدهای اولینشی ایجاد شده از کالس )‪ Person (first Person‬اختصاص‬
‫داده شده است‪ .‬برای دسترسی به فیلدها یا متدهای یک شیء از عالمت نقطه (دات) استفاده میشود‪ .‬به عنوان مثال کد ‪ name.firstPerson‬نشان دهنده‬
‫فیلد ‪ name‬از شی ‪ firstPerson‬میباشد‪ .‬برای چاپ مقادیر فیلدها باید متد )(‪ TellInformation‬شی ‪ firstPerson‬را فراخوانی میکنیم‪ .‬در خطوط‬
‫‪ 34-31‬نیز مقادیری به شی دومی که قبالً از کالس ایجاد شده تخصیص میدهیم و سپس متد )(‪ TellInformation‬را فراخوانی میکنیم‪ .‬به این نکته‬
‫توجه کنید که ‪ firstPerson‬و ‪ secondPerson‬نسخههای متفاوتی از هر فیلد دارند بنابراین تعیین یک نام برای ‪ secondPerson‬هیچ تاثیری بر نام‬
‫‪ firstPerson‬ندارد‪ .‬در مورد اعضای کالس در درسهای آینده توضیح خواهیم داد‪.‬‬

‫سازنده ها (‪)Constructors‬‬

‫سازندهها متدهای خاصی هستند که وجود آنها برای ساخت اشیا الزم است‪ .‬آنها به شما اجازه میدهند که مقادیری را به هر یک از اعضای دادهای یک آرایه‬
‫اختصاص دهید و کدهایی که را که میخواهید هنگام ایجاد یک شیء اجرا شوند را به برنامه اضافه کنید‪ .‬اگر از هیچ سازندهای در کالستان استفاده نکنید‪ ،‬کامپایلر‬
‫از سازنده پیشفرض که یک سازنده بدون پارامتر است استفاده میکند‪ .‬میتوانید در برنامهتان از تعداد زیادی سازنده استفاده کنید که دارای پارامترهای متفاوتی‬
‫باشند‪ .‬در مثال زیر یک کالس که شامل سازنده است را مشاهده میکنید‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Person‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;‪public string name‬‬
‫‪6:‬‬ ‫;‪public int age‬‬
‫‪7:‬‬ ‫;‪public double height‬‬
‫‪8:‬‬
‫‪9:‬‬ ‫‪//Explicitly declare a default constructor‬‬
‫‪10:‬‬ ‫)(‪public Person‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫}‬
‫‪13:‬‬
‫‪14:‬‬ ‫‪//Constructor that has 3 parameters‬‬
‫‪15:‬‬ ‫)‪public Person(string n, int a, double h‬‬
‫‪16:‬‬ ‫{‬
‫‪17:‬‬ ‫;‪name = n‬‬

‫‪129‬‬
‫‪18:‬‬ ‫;‪age = a‬‬
‫‪19:‬‬ ‫;‪height = h‬‬
‫‪20:‬‬ ‫}‬
‫‪21:‬‬
‫‪22:‬‬ ‫)(‪public void ShowInformation‬‬
‫‪23:‬‬ ‫{‬
‫‪24:‬‬ ‫;)‪Console.WriteLine("Name: {0}", name‬‬
‫‪25:‬‬ ‫;)‪Console.WriteLine("Age: {0} years old", age‬‬
‫‪26:‬‬ ‫;)‪Console.WriteLine("Height: {0}cm", height‬‬
‫‪27:‬‬ ‫}‬
‫} ‪28:‬‬
‫‪29:‬‬
‫‪30: public class Program‬‬
‫{ ‪31:‬‬
‫‪32:‬‬ ‫)(‪public static void Main‬‬
‫‪33:‬‬ ‫{‬
‫‪34:‬‬ ‫;)(‪Person firstPerson = new Person‬‬
‫‪35:‬‬ ‫;)‪Person secondPerson = new Person("Mike", 23, 158‬‬
‫‪36:‬‬
‫‪37:‬‬ ‫;"‪firstPerson.name = "Jack‬‬
‫‪38:‬‬ ‫;‪firstPerson.age = 21‬‬
‫‪39:‬‬ ‫;‪firstPerson.height = 160‬‬
‫‪40:‬‬ ‫;)(‪firstPerson.ShowInformation‬‬
‫‪41:‬‬
‫‪42:‬‬ ‫‪Console.WriteLine(); //Seperator‬‬
‫‪43:‬‬
‫‪44:‬‬ ‫;)(‪secondPerson.ShowInformation‬‬
‫‪45:‬‬ ‫}‬
‫} ‪46:‬‬

‫‪Name: Jack‬‬
‫‪Age: 21 years old‬‬
‫‪Height: 160cm‬‬

‫‪Name: Mike‬‬
‫‪Age: 23 years old‬‬
‫‪Height: 158cm‬‬
‫همانطور که مشاهده میکنید در مثال باال دو سازنده را به کالس ‪ Person‬اضافه کردهایم‪ .‬یکی از آنها سازنده پیشفرض (خطوط ‪ )10-12‬و دیگری سازندهای‬
‫‪.)15‬‬ ‫‪-20‬‬ ‫(خطوط‬ ‫میکند‬ ‫قبول‬ ‫آرگومان‬ ‫سه‬ ‫که‬ ‫است‬
‫به این نکته توجه کنید که سازنده درست شبیه به یک متد است با این تفاوت که‬

‫نه مقدار برگشتی دارد و نه از نوع ‪ void‬است‪.‬‬ ‫•‬


‫نام سازنده باید دقیقاً شبیه نام کالس باشد‪.‬‬ ‫•‬

‫سازنده پیشفرض در داخل بدنهاش هیچ چیزی ندارد و وقتی فراخوانی میشود که ما از هیچ سازندهای در کالسمان استفاده نکنیم‪ .‬در آینده متوجه میشوید که‬
‫چطور میتوان مقادیر پیشفرضی به اعضای دادهای اختصاص داد‪ ،‬وقتی که از یک سازنده پیشفرض استفاده میکنید‪ .‬به دومین سازنده توجه کنید‪ .‬اوالً که نام آن‬
‫شبیه نام سازنده اول است‪ .‬سازندهها نیز مانند متدها میتوانند سربارگذاری شوند‪ .‬حال اجازه دهید که چطور میتوانیم یک سازنده خاص را هنگام تعریف یک‬
‫نمونه از کالس فراخوانی کنیم‪.‬‬

‫;)(‪Person firstPerson = new Person‬‬


‫‪130‬‬
‫;)‪Person secondPerson = new Person("Mike", 23, 158‬‬

‫در اولین نمونه ایجاد شده از کالس ‪ Person‬از سازنده پیشفرض استفاده کردهایم چون پارامتری برای دریافت آرگومان ندارد‪ .‬در دومین نمونه ایجاد شده‪ ،‬از‬
‫سازندهای استفاده میکنیم که دارای سه پارامتر است‪ .‬کد زیر تأثیر استفاده از دو سازنده مختلف را نشان میدهد ‪:‬‬

‫;"‪firstPerson.name = "Jack‬‬
‫;‪firstPerson.age = 21‬‬
‫;‪firstPerson.height = 160‬‬
‫;)(‪firstPerson.ShowInformation‬‬

‫‪Console.WriteLine(); //Seperator‬‬

‫;)(‪secondPerson.ShowInformation‬‬

‫همانطور که مشاهده میکنید الزم است که به فیلدهایشی ای که از سازنده پیشفرض استفاده میکند مقادیری اختصاص داده شود تا اینشی نیز با فراخوانی متد‬
‫)(‪ ShowInformation‬آنها را نمایش دهد‪ .‬حال به شی دوم که از سازنده دارای پارامتر استفاده میکند توجه کنید‪ ،‬مشاهده میکنید که با فراخوانی متد‬
‫)(‪ ShowInformation‬همه چیز همانطور که انتظار میرود اجرا میشود‪ .‬این بدین دلیل است که شما هنگام تعریف نمونه و از قبل مقادیری به هر یک از‬
‫فیلدها اختصاص داده اید بنابراین آنها نیاز به مقدار دهی مجدد ندارند مگر اینکه شما بخواهید این مقادیر را اصالح کنید‪.‬‬

‫اختصاص مقادیر پیشفرض به سازنده پیشفرض‬

‫در مثالهای قبلی یک سازنده پیشفرض با بدنه خالی نشان داده شد‪ .‬شما میتوانید به بدنه این سازنده پیشفرض کدهایی اضافه کنید‪ .‬همچنین میتوانید مقادیر‬
‫پیشفرضی به فیلدهای آن اختصاص دهید‪.‬‬

‫)(‪public Person‬‬
‫{‬
‫;"‪name = "No Name‬‬
‫;‪age = 0‬‬
‫;‪height = 0‬‬
‫}‬

‫همانطور که در مثال باال میبینید سازنده پیشفرض ما چیزی برای اجرا دارد‪ .‬اگر نمونهای ایجاد کنیم که از این سازنده پیشفرض استفاده کند‪ ،‬نمونه ایجاد شده‬
‫مقادیر پیشفرض سازنده پیشفرض را نشان میدهد‪.‬‬

‫;)(‪Person person1 = new Person‬‬

‫;)(‪person1.ShowInformation‬‬

‫‪Name: No Name‬‬
‫‪Age: 0 years old‬‬
‫‪Height: 0cm‬‬

‫استفاده از کلمه کلیدی ‪this‬‬

‫راهی دیگر برای ایجاد مقادیر پیشفرض استفاده از کلمه کلیدی ‪ this‬است‪ .‬مثال زیر اصالح شده مثال قبل است و نحوه استفاده از ‪ 4‬سازنده با تعداد پارامترهای‬
‫مختلف را نشان میدهد‪.‬‬
‫‪131‬‬
1: using System;
2:
3: public class Person
4: {
5: public string name;
6: public int age;
7: public double height;
8:
9: public Person()
10: : this("No Name", 0, 0)
11: {
12: }
13:
14: public Person(string n)
15: : this(n, 0, 0)
16: {
17: }
18:
19: public Person(string n, int a)
20: : this(n, a, 0)
21: {
22: }
23:
24: public Person(string n, int a, double h)
25: {
26: name = n;
27: age = a;
28: height = h;
29: }
30:
31: public void ShowInformation()
32: {
33: Console.WriteLine("Name: {0}", name);
34: Console.WriteLine("Age: {0} years old", age);
35: Console.WriteLine("Height: {0}cmn", height);
36: }
37: }
38:
39: public class Program
40: {
41: public static void Main()
42: {
43: Person firstPerson = new Person();
44: Person secondPerson = new Person("Jack");
45: Person thirdPerson = new Person("Mike", 23);
46: Person fourthPerson = new Person("Chris", 18, 152);
47:
48: firstPerson.ShowInformation();
49: secondPerson.ShowInformation();
50: thirdPerson.ShowInformation();
51: fourthPerson.ShowInformation();
52: }

132
‫} ‪53:‬‬

‫‪Name: No Name‬‬
‫‪Age: 0 years old‬‬
‫‪Height: 0cm‬‬

‫‪Name: Jack‬‬
‫‪Age: 0 years old‬‬
‫‪Height: 0cm‬‬

‫‪Name: Mike‬‬
‫‪Age: 23 years old‬‬
‫‪Height: 0cm‬‬

‫‪Name: Chris‬‬
‫‪Age: 18 years old‬‬
‫‪Height: 152cm‬‬
‫ما چهار سازنده بری اصالح کالسمان تعریف کردهایم‪ .‬شما می توانید تعداد زیادی سازنده برای مواقع لزوم در کالس داشته باشید‪ .‬اولین سازنده یک سازنده‬
‫پیشفرض است‪ .‬دومین سازنده یک پارامتر از نوع رشته دریافت میکند‪ .‬سومین سازنده دو پارامتر و چهارمین سازنده سه پارامتر میگیرد‪ .‬به چارمین سازنده در‬
‫خطوط ‪ 24-29‬توجه کنید‪ .‬سه سازنده دیگر به این سازنده وابسته هستند‪ .‬در خطوط ‪ 9-12‬یک سازنده پیشفرض بدون پارامتر تعریف شده است‪ .‬توجه کنید که از‬
‫کلمه کلیدی ‪ this‬باید بعد از عالمت کالن ( ‪ ) :‬استفاده کنید‪ .‬این کلمه کلیدی به شما اجازه میدهد که یک سازنده دیگر موجود در داخل کالس را فراخوانی‬
‫میدهیم‪.‬‬ ‫اختصاص‬ ‫پیشفرض‬ ‫سازنده‬ ‫طریق‬ ‫از‬ ‫فیلدها‬ ‫به‬ ‫پیشفرضی‬ ‫مقادیر‬ ‫کنید‪.‬‬
‫چون ما سه آرگومان برای پرانتزهای بعد از کلمه کلیدی ‪ this‬سازنده پیشفرض در نظر گرفتهایم در نتیجه سازندهای که دارای سه پارامتر است فراخوانی شده و‬
‫سه آرگومان به پارامترهای آن ارسال میشود‪ .‬کدهای داخل بدنه چهارمین سازنده اجرا میشوند و مقادیر پارامترهای آن به هر یک از اعضای دادهای مربوط‬
‫اختصاص داده میشود‪ .‬نمی توانیم هیچ کدی را در داخل بدنه اولین سازنده بنویسیم چون توسط سازنده چهارم اجرا میشوند‪ .‬اگر کدی در داخل بدنه سازنده‬
‫پیشفرض بنویسیم قبل از بقیه کدها اجرا میشود‪ .‬دومین سازنده (خطوط ‪ )14-17‬به یک آرگومان نیاز دارد که همان فیلد ‪ name‬کالس ‪ Person‬است‪.‬‬
‫وقتی این پارامتر با یک مقدار رشتهای پر شد‪ ،‬سپس به پارامترهای سازنده چهارم ارسال شده و در کنار دو مقدار پیشفرض دیگر (‪ 0‬برای ‪ age‬و ‪ 0‬برای‬
‫‪ )height‬قرار میگیرد‪ .‬پس در داخل بدنه دومین سازنده هم نباید کدی بنویسیم چون این کد نیز توسط سازنده چهارم اجرا میشود‪ .‬در خط ‪ 91-22‬سومین‬
‫سازنده تعریف شده است که بسیار شبیه دومین سازنده است با این تفاوت که دو پارامتر دارد‪ .‬مقدار دو پارامتر سومین سازنده به اضافهی یک مقدار پیشفرض صفر‬
‫برای سومین آرگومان‪ ،‬به چهارمین سازنده با استفاده از کلمه کلیدی ‪ this‬ارسال میشود‪.‬‬

‫;)(‪Person firstPerson = new Person‬‬


‫;)"‪Person secondPerson = new Person("Jack‬‬
‫;)‪Person thirdPerson = new Person("Mike", 23‬‬
‫;)‪Person fourthPerson = new Person("Chris", 18, 152‬‬

‫همانطور که مشاهده میکنید با ایجاد چندین سازنده برای یک کالس‪ ،‬چندین راه برای ایجاد یک شیء بر اساس دادههایی که نیاز داریم به وجود میآید‪ .‬در مثال‬
‫باال ‪ 4‬نمونه از کالس ‪ Person‬ایجاد کردهایم و چهار تغییر در سازنده آن به وجود آوردهایم‪ .‬سپس مقادیر مربوط به فیلدهای هر نمونه را نمایش میدهیم‪ .‬یکی‬
‫از موراد استفاده از کلمه کلیدی ‪ this‬به صورت زیر است‪ .‬فرض کنید نام پارامترهای متد کالس شما یا سازنده‪ ،‬شبیه نام یکی از فیلدها باشد‪.‬‬

‫)‪public Person(string name, int age, double height‬‬


‫{‬
‫;‪name = name‬‬
‫;‪age = age‬‬
‫;‪height = height‬‬
‫}‬

‫‪133‬‬
‫این نوع کدنویسی ابهام بر انگیز است و کامپایلر نمیتواند متغیر را تشخیص داده و مقداری به آن اختصاص دهد‪ .‬اینجاست که از کلمه کلیدی ‪ this‬استفاده‬
‫میکنیم‪.‬‬

‫)‪public Person(string name, int age, double height‬‬


‫{‬
‫;‪this.name = name‬‬
‫;‪this.age = age‬‬
‫;‪this.height = height‬‬
‫}‬

‫قبل از هر فیلدی کلمه کلیدی ‪ this‬را مینویسیم و نشان میدهیم که این همان چیزی است که میخواهیم به آن مقداری اختصاص دهیم‪ .‬کلمه کلیدی‬
‫‪ this‬ارجاع یک شیء به خودش را نشان میدهد‪.‬‬

‫مخرب ها (‪)Destructors‬‬

‫مخربها نقطه مقابل سازندهها هستند‪ .‬مخربها متدهای خاصی هستند که هنگام تخریب یک شیء فراخوانی میشوند‪ .‬اشیا از حافظه کامپیوتر استفاده میکنند و‬
‫اگر پاک نشوند ممکن است با کمبود حافظه مواجه شوید‪ .‬میتوان از مخربها برای پاک کردن منابعی که در برنامه مورد استفاده قرار نمیگیرند استفاده کرد‪.‬‬
‫معموالً دات نت فریم ورک به صورت اتوماتیک از زباله روب )‪ (garbage collection‬برای پاک کردن حافظه استفاده میکند و الزم نیست شما به صورت‬
‫دستی اشیا را از حافظه پاک کنید‪ .‬بعضی اوقات زباله روب کارش را به خوبی انجام نمیدهد‪ .‬به عنوان مثال وقتی یک کانکشن برای پایگاه داده میسازید و یا‬
‫یک فایل متنی را برای خواندن باز میکنید‪ .‬با استفاده از مخربها‪ ،‬کدی را تعریف میکنید که وقتی اجرا میشود که یک شیء تخریب شده باشد‪ .‬معموالً شیء‬
‫وقتی تخریب میشود که از محدوده خارج شود‪ .‬دستور نوشتن مخرب کمی با سازنده متفاوت است ‪:‬‬

‫)(‪~ClassName‬‬
‫{‬
‫;‪code to execute‬‬
‫}‬

‫مانند سازندهها‪ ،‬مخربها باید همنام کالسی باشند که در آن تعریف شدهاند‪ .‬به این نکته توجه کنید که قبل از نام مخرب عالمت (~) را درج کنید‪ .‬یک مخرب‬
‫نمیتواند دارای سطح دسترسی (مانند ‪ )public‬باشد‪ .‬برنامه زیر نحوه فراخوانی سازنده و مخرب را نشان میدهد ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Test‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public Test‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;)"‪Console.WriteLine("Constructor was called.‬‬
‫‪8:‬‬ ‫}‬
‫‪9:‬‬ ‫)(‪~Test‬‬
‫‪10:‬‬ ‫{‬
‫‪11:‬‬ ‫;)"‪Console.WriteLine("Destructor was called.‬‬
‫‪12:‬‬ ‫}‬
‫} ‪13:‬‬
‫‪14:‬‬
‫‪15: public class Program‬‬
‫{ ‪16:‬‬
‫‪17:‬‬ ‫)(‪public static void Main‬‬
‫‪134‬‬
‫‪18:‬‬ ‫{‬
‫‪19:‬‬ ‫;)(‪Test x1 = new Test‬‬
‫‪20:‬‬ ‫}‬
‫} ‪21:‬‬

‫‪Constructor was called.‬‬


‫‪Destructor was called.‬‬
‫در کالس ‪ Test‬یک سازنده و یک مخرب تعریف شده است‪ .‬سپس در داخل متد )(‪ Main‬یک نمونه از کالس ایجاد کردهایم‪ .‬وقتی یک نمونه از کالس ایجاد‬
‫میکنیم سازنده فراخوانی شده و پیغام مناسب نمایش داده میشود‪ .‬وقتی از متد )(‪ Main‬خارج میشویم نمونه ایجاد شده نابود و مخرب فراخوانی میشود‪ .‬دات‬
‫نت فریم ورک در حقیقت مخرب را به عنوان یک متد که ‪ override‬شده متد )(‪ Finalize‬است‪ ،‬به صورت زیر تفسیر میکند ‪:‬‬

‫)(‪protected override void Finalize‬‬


‫{‬
‫‪try‬‬
‫{‬
‫‪// Cleanup statements...‬‬
‫}‬
‫‪finally‬‬
‫{‬
‫;)(‪base.Finalize‬‬
‫}‬
‫}‬

‫نگران کلماتی مانند ‪ protect،Override‬و … نباشید‪ .‬در درسهای آینده در مورد آنها توضیح میدهیم‪.‬‬

‫فیلدهای فقط – خواندنی‬

‫از کلمه کلیدی ‪ readonly‬برای فیلدها استفاده میشود و اجازه تغییر مقادیر آنها را نمیدهد‪ .‬فیلدهای فقط – خواندنی از لحاظ ساختاری بسیار شبیه به ثابتها‬
‫هستند با این تفاوت که در هنگام تعریف این نوع فیلدها میتوانید به آنها مقداری اختصاص ندهید‪ .‬هر چند باید به آنها در داخل سازنده کالس مقادیری اختصاص‬
‫دهید‪ .‬بعد از تخصیص مقدار به یک فیلد فقط خواندنی نمیتوان آن را تغییر داد چون باعث بروز خطا میشود‪.‬‬

‫‪1: public class Sample‬‬


‫{ ‪2:‬‬
‫‪3:‬‬ ‫;‪readonly int y = 10‬‬
‫‪4:‬‬ ‫;‪readonly int x‬‬
‫‪5:‬‬
‫‪6:‬‬ ‫)‪public Sample(int number‬‬
‫‪7:‬‬ ‫{‬
‫‪8:‬‬ ‫;‪x = number‬‬
‫‪9:‬‬ ‫}‬
‫} ‪10:‬‬

‫در کالس باال دو فیلد فقط – خواندنی تعریف شدهاند‪ .‬اولین فیلد در هنگام تعریف مقدار گرفته است و دومین فیلد در سازنده کالس‪.‬‬

‫سطح دسترسی‬
‫‪135‬‬
‫سطح دسترسی مشخص میکند که متدها یک کالس یا اعضای دادهای در چه جای برنامه قابل دسترسی هستند‪ .‬در این درس میخواهیم به سطح دسترسی‬
‫‪ private‬و ‪ public‬نگاهی بیندازیم‪ .‬سطح دسترسی ‪ public‬زمانی مورد استفاده قرار میگیرد که شما بخواهید به یک متد یا فیلد در خارج از کالس و حتی‬
‫پروژه دسترسی یابید‪ .‬به عنوان مثال به کد زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Test‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;‪public int number‬‬
‫} ‪6:‬‬
‫‪7:‬‬
‫‪8: public class Program‬‬
‫{ ‪9:‬‬
‫‪10:‬‬ ‫)(‪public static void Main‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫;)(‪Test x = new Test‬‬
‫‪13:‬‬
‫‪14:‬‬ ‫;‪x.number = 10‬‬
‫‪15:‬‬ ‫}‬
‫} ‪16:‬‬

‫در این مثال کالس ‪ Test‬را به صورت ‪ public‬تعریف کردهایم‪ .‬این کار به کالس ‪ program‬اجازه میدهد که از کالس ‪ Test‬نمونه ایجاد کند‪ .‬سپس یک‬
‫عضو دادهای به صورت ‪ public‬در داخل کالس ‪ Test‬تعریف میکنیم (خط ‪ .)5‬با تعریف این عضو به صورت ‪ public‬میتوانیم آن را در خارج از کالس‬
‫‪ Test‬و در داخل متد )(‪ Main‬کالس ‪ program‬مقدار دهی کنیم‪ .‬اگر از کلمه کلیدی ‪ public‬استفاده نکنیم نمیتوانیم در داخل کالس ‪program‬‬
‫نمونهای از کالس ‪ Test‬ایجاد کنیم و به اعضای آن دسترسی یابیم و این به نوعی به معنی استفاده از سطح دسترسی ‪ private‬میباشد‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: private class Test‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;‪public int number‬‬
‫} ‪6:‬‬
‫‪7:‬‬
‫‪8: public class Program‬‬
‫{ ‪9:‬‬
‫‪10:‬‬ ‫)(‪public static void Main‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫;)(‪Test x = new Test‬‬
‫‪13:‬‬
‫‪14:‬‬ ‫;‪x.number = 10‬‬
‫‪15:‬‬ ‫}‬
‫} ‪16:‬‬

‫همانطور که در مثال باال مشاهده میکنید این بار از کلمه ‪ private‬در کالس ‪ Test‬استفاده کردهایم (خط ‪ .)3‬وقتی که برنامه را کامپایل میکنیم با حطا مواجه‬
‫میشویم چون کالس ‪ Test‬در داخل کالس ‪ program‬و یا هر کالس دیگر قابل دسترسی نیست‪ .‬به این نکته توجه کنید که با اینکه عضو دادهای کالس‬
‫‪ Test‬به صورت ‪ public‬تعریف شده است باز هم نمیتوان به آن در داخل کالس ‪ program‬دسترسی یافت چون کالسی که در داخل آن قرار دارد از نوع‬
‫‪ private‬است در نتیجه تمام اعضای مربوطه در خارج از آن غیر قابل دسترسی هستند‪ .‬نکته دیگر اینکه اگر شما برای یک کالس سطح دسترسی تعریف نکنید‬
‫آن کالس دارای سطح دسترسی داخلی (‪ )internal‬میشود به این معنی که فقط کالسهای داخل پروژهای که با آن کار میکنید و میتوانند به آن کالس‬

‫‪136‬‬
‫دسترسی یابند‪ .‬استفاده از سطح دسترسی ‪ internal‬معادل استفاده از سطح دسترسی ‪ public‬است با این تفاوت که در خارج از پروژه قابل دسترسی نیست‪.‬‬
‫کدهای زیر دارای تأثیر یکسانی هستند‪.‬‬

‫‪class Test‬‬
‫{‬
‫}‬
‫‪internal class Test‬‬
‫{‬
‫}‬

‫اگر یک کالس را به صورت ‪ public‬و اعضای آن را به صورت ‪ private‬تعریف کنیم‪ ،‬آنگاه میتوان یک نمونه از کالس را در داخل کالسهای دیگر ایجاد‬
‫کرد ولی اعضای آن قابل دسترسی نیستند‪ .‬اعضای دادهای ‪ private‬فقط به وسیله متد داخل کالس ‪ Test‬قابل دسترسی هستند‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Test‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;‪private int number‬‬
‫} ‪6:‬‬
‫‪7:‬‬
‫‪8: public class Program‬‬
‫{ ‪9:‬‬
‫‪10:‬‬ ‫)(‪public static void Main‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫;)(‪Test x = new Test‬‬
‫‪13:‬‬
‫‪14:‬‬ ‫‪x.number = 10; //Error, number is private‬‬
‫‪15:‬‬ ‫}‬
‫} ‪16:‬‬

‫سطوح دسترسی دیگری هم در سی شارپ وجود دارد که بعد از مبحث وراثت در درسهای آینده در مورد آنها توضیح خواهیم داد‪.‬‬

‫کپسوله کردن (‪)Encapsulation‬‬

‫کپسوله کردن (تلفیق داده ها با یکدیگر) یا مخفی کردن اطالعات فرایندی است که طی آن اطلالعات حساس یک موضوع از دید کاربر مخفی میشود و فقط‬
‫اطالعاتی که الزم باشد برای او نشان داده میشود‪.‬‬
‫وقتی که یک کالس تعریف میکنیم معموالً تعدادی اعضای دادهای (فیلد) برای ذخیره مقادیر مربوط به شی نیز تعریف میکنیم‪ .‬برخی از این اعضای دادهای‬
‫توسط خود کالس برای عملکرد متدها و برخی دیگر از آنها به عنوان یک متغیر موقت به کار میروند‪ .‬به این اعضای دادهای‪ ،‬اعضای مفید نیز می گویند چون‬
‫فقط در عملکرد متدها تأثیر دارند و مانند یک داده قابل رویت کالس نیستند‪ .‬الزم نیست که کاربر به تمام اعضای دادهای یا متدهای کالس دسترسی داشته‬
‫باشد‪ .‬اینکه فیلدها را طوری تعریف کنیم که در خارج از کالس قابل دسترسی باشند بسیار خطرناک است چون ممکن است کاربر رفتار و نتیجه یک متد را تغییر‬
‫دهد‪ .‬به برنامه ساده زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Test‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;‪public int five = 5‬‬

‫‪137‬‬
‫‪6:‬‬
‫‪7:‬‬ ‫)‪public int AddFive(int number‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫;‪number += five‬‬
‫‪10:‬‬ ‫;‪return number‬‬
‫‪11:‬‬ ‫}‬
‫} ‪12:‬‬
‫‪13:‬‬
‫‪14: public class Program‬‬
‫{ ‪15:‬‬
‫‪16:‬‬ ‫)(‪public static void Main‬‬
‫‪17:‬‬ ‫{‬
‫‪18:‬‬ ‫;)(‪Test x = new Test‬‬
‫‪19:‬‬
‫‪20:‬‬ ‫;‪x.five = 10‬‬
‫‪21:‬‬ ‫;))‪Console.WriteLine(x.AddFive(100‬‬
‫‪22:‬‬ ‫}‬
‫} ‪23:‬‬

‫‪110‬‬
‫متد داخل کالس ‪ Test‬به نام ‪ AddFive‬دارای هدف سادهای است و آن اضافه کردن مقدار ‪ 5‬به هر عدد میباشد‪ .‬در داخل متد )(‪ Main‬یک نمونه‬
‫از کالس ‪ Test‬ایجاد کردهایم و مقدار فیلد آن را از ‪ 5‬به ‪ 10‬تغییر میدهیم (در اصل نباید تغییر کند چون ما از برنامه خواستهایم هر عدد را با ‪ 5‬جمع کند‬
‫ولی کاربر به راحتی آن را به ‪ 10‬تغییر میدهد)‪ .‬همچنین متد )(‪ AddFive‬را فراخوانی و مقدار ‪ 100‬را به آن ارسال میکنیم‪ .‬مشاهده میکنید که قابلیت‬
‫متد )(‪ AddFive‬به خوبی تغییر میکند و شما نتیجه متفاوتی مشاهده میکنید‪ .‬اینجاست که اهمیت کپسوله سازی مشخص میشود‪ .‬اینکه ما در‬
‫درسهای قبلی فیلدها را به صورت ‪ public‬تعریف کردیم و به کاربر اجازه دادیم که در خارج از کالس به آنها دسترسی داشته باشد کار اشتباهی بود‪.‬‬
‫فیلدها باید همیشه به صورت ‪ private‬تعریف شوند‪.‬‬

‫خواص (‪)Properties‬‬

‫‪( property‬خصوصیت) استانداردی در سی شارپ‪ ،‬برای دسترسی به اعضای دادهای (فیلدها) با سطح دسترسی ‪ private‬در داخل یک کالس میباشد‪.‬‬
‫همانطور که در درس قبل اشاره شد‪ ،‬تعریف فیلدها در داخل کالس به صورت ‪ public‬اشتباه است‪ ،‬چون کاربران میتوانند با ایجاد یک شیء از کالس به آنها‬
‫دسترسی داشته باشند و هر مقداری که دوست دارند به آنها اختصاص دهند‪ .‬برای رفع این مشکل مفهوم ‪ property‬ارائه شد‪ .‬هر ‪ property‬دارای دو بخش‬
‫میباشد‪ ،‬یک بخش جهت مقدار دهی (بلوک ‪ )set‬و یک بخش برای دسترسی به مقدار (بلوک ‪ )get‬یک داده ‪ private‬میباشد‪ property .‬ها باید به‬
‫صورت ‪ public‬تعریف شوند تا در کالسهای دیگر نیز قابل دسترسی میباشند‪ .‬در مثال زیر نحوه تعریف و استفاده از ‪ property‬آمده است ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: namespace PropertiesDemo‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫‪public class Person‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪private string name‬‬
‫‪8:‬‬ ‫;‪private int age‬‬
‫‪9:‬‬ ‫;‪private double height‬‬
‫‪10:‬‬
‫‪11:‬‬ ‫‪public string Name‬‬
‫‪138‬‬
12: {
13: get
14: {
15: return name;
16: }
17: set
18: {
19: name = value;
20: }
21: }
22:
23: public int Age
24: {
25: get
26: {
27: return age;
28: }
29: set
30: {
31: age = value;
32: }
33: }
34:
35: public double Height
36: {
37: get
38: {
39: return height;
40: }
41: set
42: {
43: height = value;
44: }
45: }
46:
47: public Person(string name, int age, double height)
48: {
49: this.name = name;
50: this.age = age;
51: this.height = height;
52: }
53:
54: }
55:
56: public class Program
57: {
58: public static void Main()
59: {
60: Person person1 = new Person("Jack", 21, 160);
61: Person person2 = new Person("Mike", 23, 158);
62:
63: Console.WriteLine("Name: {0}", person1.Name);
64: Console.WriteLine("Age: {0} years old", person1.Age);

139
65: Console.WriteLine("Height: {0}cm", person1.Height);
66:
67: Console.WriteLine(); //Seperator
68:
69: Console.WriteLine("Name: {0}", person2.Name);
70: Console.WriteLine("Age: {0} years old", person2.Age);
71: Console.WriteLine("Height: {0}cm", person2.Height);
72:
73: person1.Name = "Frank";
74: person1.Age = 19;
75: person1.Height = 162;
76:
77: person2.Name = "Ronald";
78: person2.Age = 25;
79: person2.Height = 174;
80:
81: Console.WriteLine(); //Seperator
82:
83: Console.WriteLine("Name: {0}", person1.Name);
84: Console.WriteLine("Age: {0} years old", person1.Age);
85: Console.WriteLine("Height: {0}cm", person1.Height);
86:
87: Console.WriteLine();
88:
89: Console.WriteLine("Name: {0}", person2.Name);
90: Console.WriteLine("Age: {0} years old", person2.Age);
91: Console.WriteLine("Height: {0}cm", person2.Height);
92: }
93: }
94: }

Name: Jack
Age: 21 years old
Height: 160cm

Name: Mike
Age: 23 years old
Height: 158cm

Name: Frank
Age: 19 years old
Height: 162cm

Name: Ronald
Age: 25 years old
Height: 174cm
‫) تعریف کردهایم (سه فیلد با سطح‬7-9 ‫ همانطور که مشاهده میکنید در این برنامه ما سه فیلد (خطوط‬.‫ آمده است‬property ‫در برنامه باال نحوه استفاده از‬
.)private ‫دسترسی‬

private string name;


private int age;
private double height;

140
‫دسترسی به مقادیر این فیلدها فقط از طریق ‪ property‬های ارائه شده (خطوط ‪ )11-45‬امکان پذیر است‪.‬‬

‫‪public string Name‬‬


‫{‬
‫‪get‬‬
‫{‬
‫;‪return name‬‬
‫}‬
‫‪set‬‬
‫{‬
‫;‪name = value‬‬
‫}‬
‫}‬

‫‪public int Age‬‬


‫{‬
‫‪get‬‬
‫{‬
‫;‪return age‬‬
‫}‬
‫‪set‬‬
‫{‬
‫;‪age = value‬‬
‫}‬
‫}‬

‫‪public double Height‬‬


‫{‬
‫‪get‬‬
‫{‬
‫;‪return height‬‬
‫}‬
‫‪set‬‬
‫{‬
‫;‪height = value‬‬
‫}‬
‫}‬

‫وقتی یک خاصیت ایجاد میکنیم‪ ،‬باید سطح دسترسی آن را ‪ public‬تعریف کرده و نوع دادهای را که بر میگرداند یا قبول میکند را مشخص کنیم‪ .‬به این‬
‫نکته توجه کنید که نام ‪ property‬ها همانند نام فیلدهای مربوطه میباشد با این تفاوت که حرف اول آنها بزرگ نوشته میشود‪ .‬البته یادآور میشویم که‬
‫شباهت نام ‪ property‬ها و فیلدها اجبار نیست و یک قرارداد در سی شارپ میباشد‪.‬‬
‫در داخل بدنه دو بخش میبینید‪ ،‬یکی بخش ‪ set‬و دیگری بخش ‪.get‬‬

‫بخش ‪ ، set‬که با کلمه کلیدی ‪ set‬نشان داده شده است برای مقدار دهی به فیلدها (اعضای دادهای) به کار میرود‪.‬‬
‫بخش ‪ ، get‬که با کلمه کلیدی ‪ get‬نشان داده شده است به شما اجازه میدهد که یک مقدار را از فیلدها (اعضای دادهای) استخراج کنید‪.‬‬

‫به کلمه کلیدی ‪ value‬در داخل بلوک ‪ set‬توجه کنید‪ Value .‬همان مقداری است که از طریق ‪ property‬به فیلد اختصاص میدهیم‪ .‬برای اختصاص یک‬
‫مقدار به یک فیلد از طریق ‪ property‬کافیست که به صورت زیر عمل کنید ‪:‬‬

‫‪141‬‬
‫;‪Object.Property = Value‬‬

‫این کار (قرار دادن یک مقدار بعد از عالمت مساوی) به منزله فراخوانی بخش ‪ set‬است‪ .‬و ما به برنامه میفهمانیم که میخواهیم از طریق بخش ‪ set‬یک فیلد‬
‫را مقداردهی کنیم‪ Object .‬شیء ایجاد شده از کالس‪ Property ،‬نام پراپرتی و ‪ Value‬مقداری است که میخواهیم به فیلد اختصاص دهیم‪ .‬برای‬
‫دسترسی به یک خاصیت میتوانید از عالمت دات (‪ ).‬استفاده کنید‪ .‬مثالً برای اختصاص مقدار به سه فیلد ‪ name ،age‬و ‪ height‬از طریق ‪ property‬باید‬
‫به صورت زیر عمل کنید ‪:‬‬

‫;"‪person1.Name = "Frank‬‬
‫;‪person1.Age = 19‬‬
‫;‪person1.Height = 162‬‬

‫دستورات باال بخش ‪ set‬مربوط به هر ‪ property‬را فراخوانی کرده و مقادیری به هر یک از فیلدها اختصاص میدهد‪ .‬برای فراخوانی بخش ‪ get‬کافیست که‬
‫نام شیء و سپس عالمت نقطه و در آخر نام ‪ property‬را بنویسیم‪ .‬با این کار به برنامه میفهمانیم که ما نیاز به مقدار فیلد داریم‪.‬‬

‫;)‪Console.WriteLine("Name: {0}", person1.Name‬‬


‫;)‪Console.WriteLine("Age: {0} years old", person1.Age‬‬
‫;))‪Console.WriteLine("Height: {0}cm", person1.Height‬‬

‫به این نکته توجه کنید که در بخش ‪ get‬هم می توان تغییراتی بر روی فیلدها اعمال کرد‪ .‬مثالً فرض کنید که یک فیلد دارید که مقادیر پولی را در خود ذخیره‬
‫میکند‪ .‬شما میتوانید در بخش ‪ get‬نحوه نمایش مقدار موجود در این فیلد را مشخص کنید‪ .‬مثالً خروجی به صورت سه رقم سه رقم نمایش داده شود‪ .‬استفاده‬
‫از ‪ property‬ها کد نویسی را انعطاف پذیر میکند مخصوصاً اگر بخواهید یک اعتبارسنجی برای اختصاص یک مقدار به فیلدها یا استخراج یک مقدار از آنها‬
‫ایجاد کنید‪ .‬پس میتوان گفت که ‪:‬‬
‫کاربرد اصلی ‪ property‬ها‪ ،‬اعتبار سنجی مقادیری است که کاربر میخواهد به فیلدها اختصاص دهد‪.‬‬
‫مثالً شما میتوانید یک محدودیت ایجاد کنید که فقط اعداد مثبت به فیلد ‪( age‬سن) اختصاص داده شود‪ .‬همانطور که در کد ابتدای درس مشاهده میکنید ما‬
‫نوع فیلد ‪ age‬را ‪ int‬قرار دادهایم‪ .‬یعنی کاربر میتواند هر رقمی بین اعداد ‪ -2147483648‬تا ‪ 2147483647‬را به این فیلد اختصاص دهد‪ .‬ولی چون غیر‬
‫معقوالنه است و سن (‪ )age‬باید یک عدد مثبت و از لحاظ عقلی عددی از ‪ 1‬تا ‪ 100‬باشد میتوانیم کاربر را با استفاده از بخش ‪ set‬مجبور کنیم که رقمی بین‬
‫این دو عدد را به ‪ age‬اختصاص دهد‪ .‬میتوانید با تغییر بخش ‪ set‬خاصیت ‪ Age‬این کار را انجام دهید ‪:‬‬

‫‪1: public int Age‬‬


‫{ ‪2:‬‬
‫‪3:‬‬ ‫‪get‬‬
‫‪4:‬‬ ‫{‬
‫‪5:‬‬ ‫;‪return age‬‬
‫‪6:‬‬ ‫}‬
‫‪7:‬‬ ‫‪set‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫)‪if (value > 0 && value <= 100‬‬
‫‪10:‬‬ ‫;‪age = value‬‬
‫‪11:‬‬ ‫‪else‬‬
‫‪12:‬‬ ‫;‪age = 0‬‬
‫‪13:‬‬ ‫}‬
‫} ‪14:‬‬

‫‪142‬‬
‫حال اگر کاربر بخواهد یک مقدار منفی به فیلد ‪ age‬اختصاص دهد مقدار ‪ age‬صفر خواهد شد‪ .‬همچنین میتوان یک ‪ property‬فقط خواندنی ‪(read-‬‬
‫)‪ only‬ایجاد کرد‪ .‬این ‪ property‬فاقد بخش ‪ set‬است‪ .‬به عنوان مثال میتوان یک خاصیت ‪ Name‬فقط خواندنی مانند زیر ایجاد کرد ‪:‬‬

‫‪public string Name‬‬


‫{‬
‫‪get‬‬
‫{‬
‫;‪return name‬‬
‫}‬
‫}‬

‫در این مورد اگر بخواهید یک مقدار جدید به فیلد ‪ name‬اختصاص دهید با خطا مواجه میشوید‪ .‬نکته دیگری که باید به آن توجه کنید این است که شما‬
‫میتوانید برای بخش ‪ set‬یا ‪ get‬سطح دسترسی ایجاد کنید‪ .‬به تکه کد زیر توجه کنید ‪:‬‬

‫‪public string Name‬‬


‫{‬
‫‪get‬‬
‫{‬
‫;‪return name‬‬
‫}‬
‫‪private set‬‬
‫{‬
‫;‪name = value‬‬
‫}‬
‫}‬

‫خاصیت ‪ Name‬فقط در خارج از کالس قابل خواندن است اما متدها فقط داخل کالس ‪ Person‬میتوانند مقادیر جدید بگیرند‪ .‬یک ‪ property‬میتواند‬
‫دارای دو فیلد باشد‪ .‬به کد زیر توجه کنید ‪:‬‬

‫;‪private string firstName‬‬


‫;‪private string lastName‬‬

‫‪public FullName‬‬
‫{‬
‫} ;‪get { return firstName + " " + lastName‬‬
‫}‬

‫همانطور که در مثال باال مشاهده میکنید یک ‪ property‬فقط خواندنی تعریف کردهایم که مقدار برگشتی آن ترکیبی از دو فیلد ‪ firstName‬و‬
‫‪ lastName‬است که به وسیله فاصله از هم جدا شدهاند‪ .‬سی شارپ همچنین یک راه حل کوتاه برای ایجاد ‪ property‬ارائه میدهد‪ .‬در این روش میتوانید‬
‫یک ‪ property‬بد ون فیلد ایجاد کنید‪ .‬گاهی اوقات ممکن است که شما اصالً نخواهید اعتبار سنجی انجام دهید‪ .‬در این صورت بهتر است که آینده نگر باشید و‬
‫باز هم به ازای هر فیلد موجود در کالس یک خاصیت تعریف کنید‪ .‬البته برای کاهش کدنویسی‪ ،‬میتوانید از نوع خالصه شده ‪ property‬ها یعنی ‪property‬‬
‫های خودکار استفاده کنید ‪:‬‬

‫} ;‪public int MyProperty { get; set‬‬

‫این ویژگی فراخوانی خودکار ‪ property‬نام دارد و در سی شارپ ‪ 3٫0‬معرفی شده است‪ .‬به این نکته توجه کنید که در این روش هیچ کدی برای بخش ‪ set‬و‬
‫‪ get‬نمینویسیم‪ .‬دستور باال معادل تعریف یک فیلد از نوع ‪ int‬با سطح دسترسی ‪ private‬است و ‪ property‬مربوط در یک خط مختصر نوشته شده و اجرا‬
‫میشود‪ .‬کامپایلر کد باال را به صورت خودکار به عنوان یک ‪ property‬شناسایی میکند و فیلد مربوط به آن در طول زمان اجرای برنامه ساخته میشود‪ .‬توجه‬

‫‪143‬‬
‫کنید وقتی یک ‪ property‬خودکار ایجاد میکنید باید هر دو بخش ‪ get‬و ‪ set‬آن را نیز تعریف کنید‪ .‬همچنین نباید هیچ کدی در داخل این دو بخش بنویسید‪.‬‬
‫بعدها اگر الزم بود که برای فیلدها اعتبارسنجی صورت بگیرد‪ ،‬میتوانید بدون اینکه کدی که از کالس استفاده میکند نیاز به تغییری داشته باشد‪property ،‬‬
‫های خودکار را به صورت ‪ property‬های معمولی ولی با اعتبارسنجی بنویسید‪.‬‬

‫فضای نام‬

‫فضای نام راهی برای دسته بندی کدهای برنامه می باشد‪ .‬هر چیز در دات نت حداقل در یک فضای نام قرار دارد‪ .‬وقتی برای یک کالس اسمی انتخاب میکنید‬
‫ممکن است برنامه نویسان دیگر به صورت اتفاقی ا سمی شبیه به آن برای کالسشان انتخاب کنند‪ .‬وقتی شما از آن کالسها در برنامهتان استفاده کنید از آنجاییکه‬
‫از کالسهای همنام استفاده میکنید در برنامه ممکن است خطا به وجود آید‪.‬‬
‫فضاهای نامی از وقوع این خطاها جلوگیری کرده یا آنها را کاهش میدهند‪ .‬تا کنون و در درسهای قبلی ما فقط با یک فضای نام آشنا شدهایم و آن فضای نام‬
‫‪ System‬است که شامل تعداد زیادی کالس و متد‪ ،‬مانند کالس ‪ Console‬و متد )(‪ Writeline‬میباشد‪ .‬اما اگر یک پروژه جدید ایجاد کنید به صورت‬
‫پیشفرض یک فضای نام برای شما ایجاد خواهد شد که نام آن شبیه به نام پروژهتان میباشد‪ .‬در این درس به شما نشان میدهیم که چگونه کالسهایتان در‬
‫کدهای جداگانه بنویسید و سپس از آنها در فایلهای جدا استفاده کنید‪ .‬برنامه ‪ Visual Studio Community‬را اجرا و یک پروژه جدید ایجاد کنید‪ .‬بعد از‬
‫اینکه پروژه ایجاد شد‪ ،‬یک فایل جدید ایجاد کنید‪ .‬چندین راه برای ایجاد یک فایل وجود دارد‪ .‬یکی از راهها این است که بر روی پروژهتان در ‪Solution‬‬
‫‪ Explorer‬راست کلیک کرده و سپس گزینه ‪ Add‬و بعد ‪ New Item‬را انتخاب کنید‪.‬‬

‫راه دیگر این است که از نوار منو بر و از گزینه ‪ Project‬بر روی دکمه ‪ Add New Item‬کلیک کنید‪:‬‬

‫‪144‬‬
‫همچنین میتوان از دکمهتر کیبی ‪ Ctrl + Shift + A‬استفاده کرد‪ .‬هر کدام از این راه ها را که انتخاب کنید در نهایت یک صفحه برای شما نشان داده‬
‫میشود و از شما سؤال میشود که چه فایلی را میخواهید ایجاد کنید ‪:‬‬

‫گزینه ‪ Class‬را انتخاب کرده و نام آنرا ‪ Sample.cs‬بگذارید کدهای سی شارپ دارای پسوند ‪ cs‬هستند‪ .‬برای درک منظور این درس همه کدهایی که در‬
‫هنگام ایجاد کالس به وجود میآیند را حذف کنید و کدهای زیر را وارد کنید ‪:‬‬

‫‪1: namespace MyNamespace‬‬


‫{ ‪2:‬‬

‫‪145‬‬
‫‪3:‬‬ ‫‪class Sample‬‬
‫‪4:‬‬ ‫{‬
‫‪5:‬‬ ‫)(‪public void ShowMessage‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;)"!‪System.Console.WriteLine("Hello World‬‬
‫‪8:‬‬ ‫}‬
‫‪9:‬‬ ‫}‬
‫} ‪10:‬‬

‫همانطور که در کد باال مشاهده میکنید فضای ناممان را تعریف کرده و نام آن را ‪ MyNamespace‬میگذاریم‪ .‬در داخل کالسمان (‪ )Sample‬یک متد‬
‫برای نمایش پیغام وجود دارد‪ .‬به این نکته توجه کنید که با استفاده از فضای نام ‪ ،System‬به متد )(‪ WriteLine‬کالس ‪ Console‬دسترسی یافتهایم‪.‬‬
‫میتوانید با استفاده از کلمه کلیدی ‪ using‬فضای نام را از قبل تعریف کنید و آن را هنگام فراخوانی متد )(‪ WriteLine‬ننویسید (کد زیر)‪ .‬حال به فایل‬
‫‪ Program.cs‬برنامهای که قبالً ایجاد کردید بروید‪ .‬محتویات آنرا پاک کرده و کدهای زیر را مینویسید ‪:‬‬

‫;‪1: using MyNamespace‬‬


‫‪2:‬‬
‫‪3: class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;)(‪Sample test = new Sample‬‬
‫‪8:‬‬
‫‪9:‬‬ ‫;)(‪test.ShowMessage‬‬
‫‪10:‬‬ ‫}‬
‫} ‪11:‬‬

‫!‪Hello World‬‬
‫با استفاده از کلمه کلیدی ‪ using‬همه محتویات فضای نام ‪ MyNamespace‬را که قبالً ایجاد کردیم وارد برنامه جدید میکنیم (خط ‪ .)1‬اگر خط اول کد‬
‫باال را حذف کنیم‪ ،‬برای استفاده از هر چیز باید قبل از ‪ Sample‬از کلمه ‪ MyNamespace‬استفاده کنیم‪.‬‬

‫;)(‪MyNamespace.Sample test = new MyNamespace.Sample‬‬

‫میتوان چندین کالس یا رابط (‪ )interface‬را به یک فضای نام اضافه کرد‪.‬‬

‫‪namespace MyNamespace‬‬
‫{‬
‫‪class Sample1‬‬
‫{‬

‫}‬

‫‪class Sample2‬‬
‫{‬

‫}‬
‫}‬

‫شما محدود به دسته بندی کدهای کالستان در داخل یک فضای نام نیستید‪ .‬میتوانید یک فضای نام تو در تو ایجاد کنید و کدهایتان را در درون آن بنویسید ‪:‬‬

‫‪namespace MyNamespace1‬‬

‫‪146‬‬
‫{‬
‫‪namespace MyNamespace2‬‬
‫{‬
‫‪class Sample‬‬
‫{‬
‫)(‪public void ShowMessage‬‬
‫{‬
‫;)"!‪System.Console.WriteLine("Hello World‬‬
‫}‬
‫}‬
‫}‬
‫}‬

‫برای دسترسی به کالس ‪ ،Sample‬مجبورید اول نام تمام فضاهای نامی را که کالس ‪ Sample‬در آنها قرار دارد بنویسید‪.‬‬

‫‪MyNamespace1.MyNamespace2.Sample‬‬

‫یا میتوان از کلمه کلیدی ‪ using‬استفاده کرد ‪:‬‬

‫;‪using MyNamespace1.MyNamespace2‬‬

‫دات نت فریم ورک دارای فضاهای نام تو در تو میباشد‪ .‬به عنوان مثال ‪ System.Data.SqlClient‬سه فضای تو در تو میباشد‪ .‬میتوان برای راحتی در‬
‫کد نویسی فضاهای نامی تو در تو‪ ،‬یک فضای نامی مستعاری ایجاد کنید ‪:‬‬

‫;‪using AliasNamespace = MyNamespace1.MyNamespace2‬‬

‫تفاوت ساختار و کالس‬

‫تفاوت بین ساختار و کالس چیست؟‬


‫ساختارها انواع مقداری هستند مانند ‪ Double ،int‬و ‪ .String‬وقتی یک مقدار از ساختار را در یک متغیر کپی میکنید‪ ،‬در اصل خود مقدار را کپی کردهاید نه‬
‫را‪.‬‬ ‫آن‬ ‫مرجع‬ ‫یا‬ ‫آدرس‬
‫کالسها انواع مرجع هستند مانند همه کالسهای دات نت‪.‬‬
‫اجازه دهید تفاوت این دو را با یک مثال توضیح دهیم ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: struct MyStructure‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫} ;‪public string Message { get; set‬‬
‫} ‪6:‬‬
‫‪7:‬‬
‫‪8: class MyClass‬‬
‫{ ‪9:‬‬
‫‪10:‬‬ ‫} ;‪public string Message { get; set‬‬
‫} ‪11:‬‬
‫‪12:‬‬
‫‪13: class Program‬‬

‫‪147‬‬
14: {
15: static void Main()
16: {
17: MyStructure structure1 = new MyStructure();
18: MyStructure structure2 = new MyStructure();
19:
20: structure1.Message = "ABC";
21: structure2 = structure1;
22:
23: Console.WriteLine("Showing that structure1 " +
24: "was copied to structure2.");
25: Console.WriteLine("structure2.Message = {0}", structure2.Message);
26:
27: Console.WriteLine("nModifying the value of structure2.Message...");
28: structure2.Message = "123";
29:
30: Console.WriteLine("nShowing that structure1 was not affected " +
31: "by the modification of structure2");
32: Console.WriteLine("structure1.Message = {0}", structure1.Message);
33:
34:
35: MyClass class1 = new MyClass();
36: MyClass class2 = new MyClass();
37:
38: class1.Message = "ABC";
39: class2 = class1;
40:
41: Console.WriteLine("nnShowing that class1 " +
42: "was copied to class2.");
43: Console.WriteLine("class2.Message = {0}", class2.Message);
44:
45: Console.WriteLine("nModifying the value of class2.Message...");
46: class2.Message = "123";
47:
48: Console.WriteLine("nShowing that class1 was also affected " +
49: "by the modification of class2");
50: Console.WriteLine("class1.Message = {0}", class1.Message);
51: }
52: }

Showing that structure1 was copied to structure2.


structure2.Message = ABC

Modifying the value of structure2.Message...

Showing that structure1 was not affected by the modification of structure2


structure1.Message = ABC

Showing that class1 was copied to class2.


class2.Message = ABC

Modifying the value of class2.Message...

148
‫‪Showing that class1 was also affected by the modification of class2‬‬
‫‪class1.Message = 123‬‬
‫در باال یک ساختار و یک کالس ایجاد کردهایم و تفاوت بین استفاده از این دو را نشان دادهایم‪ .‬یک خاصیت به نام ‪ Message‬برای هر دو قرار دادهایم‪ .‬سپس‬
‫دو نمونه از هر کدام ایجاد کردهایم (خطوط ‪ 17-18‬و ‪ .)35-36‬مقداری به خاصیت ‪ Message‬از نمونه اول ایجاد شده از ساختار (‪ )structure1‬اختصاص‬
‫میدهیم‪ .‬سپس مقدار ‪ structure1‬را برابر ‪ structure2‬قرار میدهیم‪ ،‬با این کار همه چیزهای داخل ‪ structure1‬در ‪ structure2‬کپی میشود‪.‬‬
‫برای ثابت کردن اینکه همه محتویات ‪ structure1‬کپی شده است‪ ،‬مقدار خاصیت ‪ structure2، Message‬را نشان میدهیم و مشاهده میکنیم که همان‬
‫مقدار خاصیت ‪ structure1، Message‬میباشد‪ .‬برای اثبات اینکه ساختارها انواع مقداری هستند یک پیغام دیگر را به خاصیت ‪structure2، Message‬‬
‫اختصاص میدهیم‪ .‬خاصیت ‪ structure1، Message‬تحت تأثیر قرار نمیگیرد چون ‪ structure2‬یک کپی از ‪ structure1‬میباشد‪.‬‬
‫حال اثبات میکنیم که چرا کالسها انواع مرجع هستند‪ .‬کالسها وقتی با یک متغیر برابر قرار داده میشوند آدرس خود را ارسال میکنند نه مقدارشان را‪.‬‬
‫بنابراین وقتی یک خاصیت از شیء‪ ،‬که دارای آدرس شیء اصلی است را ویرایش میکنید‪ ،‬خاصیت شیء اصلی نیز تغییر میکند‪ .‬وقتی یک شیء را به‬
‫عنوان آرگومان به متد ارسال میکنید‪ ،‬فقط آدرس شیء ارسال میشود‪ .‬هر تغییری که در شیء داخل متد به وجود بیاید‪ ،‬بر شیء اصلی که آدرس آن به‬
‫متد ارسال شده است نیز تأثیر میگذارد‪.‬‬

‫کتابخانه کالس‬

‫میتوانید کتابخانه کالسی ایجاد کنید که مجموعهای از کالسها و کدهایی است که میتوانند کامپایل شوند و در نرم افزارهای دیگر برای استفاده مجدد به کار‬
‫روند‪ .‬کتابخانههای کالس به فایلهای ‪ DLL‬کامپایل میشوند‪ DLL .‬ها با هیچ برنامهی خواندن فایل متنی قابل خواندن نیستند‪ .‬کتابخانه کالس پروژهای‬
‫است که میتوان از آن به عنوان یک راه حل شخصی برای حل مشکالت استفاده کرد‪ .‬حال یک کتابخانه کالس به روش زیر ایجاد کرده و نام آن را ‪Sample‬‬
‫میگذاریم‪ .‬به مسیر ‪ Go to File > New > Project‬میرویم ‪:‬‬

‫در لیست ظاهر شده گزینه ‪ Class Library‬را انتخاب میکنیم و همانطور که نشان داده شده است نام آن را ‪ Sample‬میگذاریم‪.‬‬

‫‪149‬‬
‫بعد از ایجاد کتابخانه کالس‪ ،‬یک کالس به طور خودکار با نام ‪ Class1‬ایجاد میشود و شما میتوانید کدهایی که الزم دارید را به آن اضافه کنید‪:‬‬

‫‪public class Class1‬‬


‫{‬
‫)(‪public void ShowMessage‬‬
‫{‬
‫;)"!‪Console.WriteLine("Hello World‬‬
‫}‬
‫}‬

‫بعد از نوشتن کدها در داخل کالس در قسمت ‪ Solution Explorer‬به مسیر ‪ Build > Build choosing‬بروید‪ .‬این کار باعث میشود که یک‬
‫فایل با پسوند ‪ DLL‬ایجاد شود که شما کدهای نوشته شده توسط شماست و میتوانید از آن در پروژههای بعدی استفاده کنید‪ .‬یک برنامه کنسولی دیگر ایجاد و‬
‫بر رو نام پروژه راست کلیک کنید و سپس به مسیر ‪ New Project > choose Add‬بروید ‪:‬‬

‫‪150‬‬
‫سپس ‪ Console Application‬را انتخاب کنید ‪:‬‬

‫بعد از ایجاد برنامه جدید‪ DLL ،‬ی را که از قبل ایجاد کردهاید به آن اضافه کنید‪ .‬برای اضافه کردن ‪ DLL‬بر روی پروژه راست کلیک کرده و مانند شکل زیر‬
‫گزینه ‪ Add Reference‬را انتخاب میکنیم ‪:‬‬

‫‪151‬‬
‫با کلیک بر روی این گزینه کادر زیر نمایش داده خواهد شد ‪:‬‬

‫به این نکته توجه کنید که همه این فایلها در حالت پیشفرض وراد پروژه شما نمیشوند‪ .‬اگر پوشه ‪ References‬داخل ‪ solution explorer‬را باز کنید‬
‫همه فایلهای اسمبلی که در دسترس شما قرار داده شده اند را مشاهده خواهید کرد‪ .‬اگر بخواهید از فایلهای اسمبلی بیشتری در دات نت استفاده کنید میتوانید آنها‬
‫را از اولین سربرگ (سربرگ ‪ )Assemblies‬به پروزه اضافه کنید‪ .‬سربرگ ‪ solution ،projects‬جاری را برای پروژههای کتابخانه کالس اسکن کرده و‬
‫بعد از یافتن‪ ،‬آنها را لیست میکند‪ .‬سومین سربرگ (‪ )Shared Projects‬برای پیدا کردن فایلهای ‪ DLL‬ی که در خارج از ‪ solution‬جاری هستند به کار‬
‫میرود‪ .‬به عنوان مثال اگر شما یک کتابخانه کالس ساده در یک ‪ solution‬جداگانه ایجاد کنید‪ ،‬میتوانید ان را وارد ‪ solution‬دیگر کرده و از آن استفاده‬
‫کنید‪ .‬سربرک ‪ Browse‬هم به شما اجازه میدهد که فایلهای ‪ DLL‬ی که قبالً در کامپیوتر ذخیره کردهاید را یافته و به برنامه اضافه کنید‪ .‬مکان فایل‬

‫‪152‬‬
‫‪ DLL.‬در داخل پوشه ‪ Debug‬یا ‪ Release‬پروژه کتابخانه کالس میباشد‪ .‬این دو پوشه نیز به نوبه خود در داخل پوشه ‪ bin‬واقع در پوشه ‪Solution‬‬
‫کتابخانه کالس قرار دارند‪.‬‬

‫بعد از زدن دکمه ‪ add‬فایل ‪ DLL‬به صورت زیر به پروژه اضافه میشود ‪:‬‬

‫حال کدهای زیر را در فایل ‪ s Program.cs’ConsoleApplication1‬بنویسید ‪:‬‬

‫;‪using Sample‬‬

‫‪namespace ConsoleApplication1‬‬
‫{‬

‫‪153‬‬
‫‪class Program‬‬
‫{‬
‫)‪static void Main(string[] args‬‬
‫{‬
‫;)(‪Class1 sampleClass = new Class1‬‬
‫;)(‪sampleClass.ShowMessage‬‬
‫}‬
‫}‬
‫}‬

‫سپس بر روی نام پروژه ‪ ConsoleApplication1‬در ‪ Solution Explorer‬راست کلیک کرده و گزینه ‪ Set as Startup Project‬را کلیک کنید‪.‬‬
‫سپس برنامه را اجرا و نتیجه را مشاهده کنید ‪:‬‬
‫!‪Hello World‬‬

‫وراثت‬

‫وراثت به یک کالس اجازه میدهد که خصوصیات یا متدهایی را از کالس دیگر به ارث برد‪ .‬وراثت مانند رابطه پدر و پسری میماند به طوریکه فرزند خصوصیاتی‬
‫از قبیل قیافه و رفتار را از پدر خود به ارث برده باشد‪.‬‬
‫کالس پایه یا کالس والد کالسی است که بقیه کالسها از آن ارث میبرند‪.‬‬
‫کالس مشتق یا کالس فرزند کالسی است که از کالس پایه ارث بری میکند‪.‬‬

‫همه متد و خصوصیات کالس پایه می توانند در کالس مشتق مورد استفاده قرار بگیرند به استثنای اعضاء و متدهای با سطح دسترسی ‪ . private‬همه کالسها‬
‫در ‪ .NET Framework‬از کالس ‪ Object‬ارث میبرند‪ .‬مفهوم اصلی وراثت در مثال زیر نشان داده شده است ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class Parent‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;‪private string message‬‬
‫‪6:‬‬
‫‪7:‬‬ ‫‪public string Message‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫} ;‪get { return message‬‬
‫‪10:‬‬ ‫} ;‪set { message = value‬‬
‫‪11:‬‬ ‫}‬
‫‪12:‬‬
‫‪13:‬‬ ‫)(‪public void ShowMessage‬‬
‫‪14:‬‬ ‫{‬
‫‪15:‬‬ ‫;)‪Console.WriteLine(message‬‬
‫‪16:‬‬ ‫}‬
‫‪17:‬‬
‫‪18:‬‬ ‫)‪public Parent(string message‬‬
‫‪19:‬‬ ‫{‬
‫‪20:‬‬ ‫;‪this.message = message‬‬
‫‪21:‬‬ ‫}‬
‫} ‪22:‬‬
‫‪23:‬‬
‫‪24: class Child : Parent‬‬

‫‪154‬‬
‫{ ‪25:‬‬
‫‪26:‬‬ ‫)‪public Child(string message) : base(message‬‬
‫‪27:‬‬ ‫{‬
‫‪28:‬‬
‫‪29:‬‬ ‫}‬
‫} ‪30:‬‬

‫در این مثال دو کالس با نامهای ‪ Parent‬و ‪ Child‬تعریف شده است‪ .‬در این مثال یک عضو را یکبار با سطح دسترسی ‪( private‬خط ‪ )5‬و یکبار با سطح‬
‫دسترسی ‪( public‬خط ‪ )7-11‬تعریف کردهایم‪ .‬سپس یک متد را برای نمایش پیام تعریف کردهایم‪ .‬یک سازنده در کالس ‪ Parent‬تعریف شده است که یک‬
‫آرگومان از نوع رشته قبول میکند و یک پیغام نمایش میدهد‪ .‬حال به کالس ‪ Child‬توجه کنید (خط ‪ .)24‬این کالس تمام متدها و خاصیتهای کالس‬
‫‪ Parent‬را به ارث برده است‪ .‬نحوه ارث بری یک کالس به صورت زیر است ‪:‬‬

‫‪class DerivedClass : BaseClass‬‬

‫براحتی میتوان با قرار دادن یک کالن ( ‪ ) :‬بعد از نام کالس و سپس نوشتن نام کالسی که از آن ارث بری میشود (کالس پایه) این کار را انجام داد‪ .‬در داخل‬
‫کالس ‪ Child‬هم یک سازنده ساده وجود دارد که یک آرگومان رشتهای قبول میکند‪ .‬وقتی از وراثت در کالسها استفاده میکنیم‪ ،‬هم سازنده کالس مشتق و‬
‫هم سازنده پیشفرض کالس پایه هر دو اجرا میشوند‪ .‬سازنده پیشفرض یک سازنده بدون پارامتر است‪ .‬اگر برای یک کالس سازندهای تعریف نکنیم کامپایلر به‬
‫صورت خودکار یک سازنده برای آن ایجاد میکند‪ .‬اگر هنگام صدا زدن سازنده کالس مشتق بخواهیم سازنده کالس پایه را صدا بزنیم باید از کلمه کلیدی ‪base‬‬
‫استفاده کنیم‪ .‬کلمه کلیدی ‪ base‬یک سازنده از کالس پایه را صدا می زند‪ .‬قبل از این کلمه کلیدی باید عالمت کالن ( ‪ ) :‬را تایپ کنیم‪.‬‬
‫در مثال باال به وسیله تأمین مقدار پارامتر ‪ message‬سازنده کالس مشتق و ارسال آن به داخل پرانتز کلمه کلیدی ‪ ، base‬سازنده معادل آن در کالس پایه‬
‫فراخوانی شده و مقدار ‪ message‬را به آن ارسال میکند‪ .‬سازنده کالس ‪ Parent‬هم این مقدار (مقدار ‪ )message‬را در یک عضو دادهای (فیلد) ‪private‬‬
‫قرار میدهد‪ .‬میتوانید کدهایی را به داخل بدنه سازنده ‪ Child‬اضافه کنید تا بعد از سا زنده ‪ Parent‬اجرا شوند‪ .‬اگر از کلمه کلیدی ‪ base‬استفاده نشود به‬
‫جای کالس پایه سازنده پیشفرض فراخوانی میشود‪ .‬اجازه بدهید که اشیایی از کالسهای ‪ Parent‬و ‪ Child‬بسازیم تا نشان دهیم که چگونه کالس ‪Child‬‬
‫متدها و خواص کالس ‪ Parent‬را به ارث میبرد‪.‬‬

‫‪1: class Program‬‬


‫{ ‪2:‬‬
‫‪3:‬‬ ‫)(‪static void Main‬‬
‫‪4:‬‬ ‫{‬
‫‪5:‬‬ ‫;)"‪Parent myParent = new Parent("Message from parent.‬‬
‫‪6:‬‬ ‫;)"‪Child myChild = new Child("Message from child.‬‬
‫‪7:‬‬
‫‪8:‬‬ ‫;)(‪myParent.ShowMessage‬‬
‫‪9:‬‬
‫‪10:‬‬ ‫;)(‪myChild.ShowMessage‬‬
‫‪11:‬‬
‫‪12:‬‬ ‫;"‪myParent.Message = "Modified message of the parent.‬‬
‫‪13:‬‬ ‫;)(‪myParent.ShowMessage‬‬
‫‪14:‬‬
‫‪15:‬‬ ‫;"‪myChild.Message = "Modified message of the child.‬‬
‫‪16:‬‬ ‫;)(‪myChild.ShowMessage‬‬
‫‪17:‬‬
‫‪18:‬‬ ‫‪//myChild.message; ERROR: can't access private members of base class‬‬
‫‪19:‬‬ ‫}‬
‫} ‪20:‬‬

‫‪Message from parent.‬‬


‫‪Message from child.‬‬

‫‪155‬‬
‫‪Modified message of the parent.‬‬
‫‪Modified message of the child.‬‬
‫هر دوشی را با استفاده از سازندههای مربوط به خودشان مقدار دهی میکنیم‪( .‬خطوط ‪ )5-6‬سپس با استفاده از ارث بری و از طریقشی ‪ Child‬به اعضاء و‬
‫متدهای کالس ‪ Parent‬دسترسی مییابیم‪ .‬حتی اگر کالس ‪ Child‬از کالس ‪ Parent‬ارث ببرد باز هم اعضای با سطح دسترسی ‪ private‬در کالس‬
‫‪ Child‬قابل دسترسی نیستند (خط ‪ .)18‬سطح دسترسی ‪ Protect‬که در درس آینده توضیح داده خواهد شد به شما اجازه دسترسی به اعضا و متدهای کالس‬
‫پایه را میدهد‪ .‬به نکته دیگر توجه کنید‪ .‬اگر کالس دیگری بخواهد از کالس ‪ Child‬ارث بری کند‪ ،‬باز هم تمام متدها و خواص کالس ‪ Child‬که از کالس‬
‫‪ Parent‬به ارث برده است را به ارث میبرد‪.‬‬

‫‪class GrandChild : Child‬‬


‫{‬
‫‪//Empty Body‬‬
‫}‬

‫این کالس هیچ چیزی در داخل بدنه ندارد‪ .‬وقتی کالس ‪ GrandChild‬را ایجاد میکنید و یک خاصیت از کالس ‪ Parent‬را فراخوانی میکنید با خطا مواجه‬
‫میشوید‪ .‬چون هیچ سازندهای که یک آرگومان رشتهای قبول کند در داخل بدنه ‪ GrandChild‬تعریف نشده است بنابراین شما میتوانید فقط از سازنده‬
‫پیشفرض یا بدون پارامتر استفاده کنید‪.‬‬

‫;)(‪GrandChild myGrandChild = new GrandChild‬‬

‫;"!‪myGrandChild.Message = "Hello my grandchild‬‬


‫;)(‪myGrandChild.ShowMessage‬‬

‫وقتی یک کالس ایجاد میکنیم و سازنده ‪ GrandChild‬را فراخوانی میکنیم ابتدا سازنده کالس ‪ Parent‬فراخوانی میشود و سپس سازنده ‪ Child‬و در‬
‫نهایت سازنده ‪ GrandChild‬اجرا میشود‪ .‬برنامه زیر ترتیب اجرای سازندهها را نشان میدهد‪ .‬دوباره کالسها را برای خوانایی بیشتر در داخل کدهای جدا قرار‬
‫میدهیم‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class Parent‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public Parent‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;)"!‪Console.WriteLine("Parent constructor was called‬‬
‫‪8:‬‬ ‫}‬
‫} ‪9:‬‬
‫‪10:‬‬
‫‪11: class Child : Parent‬‬
‫{ ‪12:‬‬
‫‪13:‬‬ ‫)(‪public Child‬‬
‫‪14:‬‬ ‫{‬
‫‪15:‬‬ ‫;)"!‪Console.WriteLine("Child constructor was called‬‬
‫‪16:‬‬ ‫}‬
‫} ‪17:‬‬
‫‪18:‬‬
‫‪19: class GrandChild : Child‬‬
‫{ ‪20:‬‬
‫‪21:‬‬ ‫)(‪public GrandChild‬‬
‫‪22:‬‬ ‫{‬
‫‪23:‬‬ ‫;)"!‪Console.WriteLine("GrandChild constructor was called‬‬
‫‪24:‬‬ ‫}‬
‫‪156‬‬
‫} ‪25:‬‬
‫‪26:‬‬
‫‪27: class Program‬‬
‫{ ‪28:‬‬
‫‪29:‬‬ ‫)(‪static void Main‬‬
‫‪30:‬‬ ‫{‬
‫‪31:‬‬ ‫;)(‪GrandChild myGrandChild = new GrandChild‬‬
‫‪32:‬‬ ‫}‬
‫} ‪33:‬‬

‫!‪Parent constructor was called‬‬


‫!‪Child constructor was called‬‬
‫!‪GrandChild constructor was called‬‬

‫سطح دسترسی ‪Protect‬‬

‫سطح دسترسی ‪ protect‬اجازه می دهد که اعضای کالس‪ ،‬فقط در کالسهای مشتق شده از کالس پایه قابل دسترسی باشند‪ .‬بدیهی است که خود کالس پایه‬
‫هم میتواند به این اعضا دسترسی داشته باشد‪ .‬کالسهایی که از کالس پایه ارث بری نکردهاند نمیتوانند به اعضای با سطح دسترسی ‪ protect‬یابند‪ .‬در مورد‬
‫سطوح دسترسی ‪ public‬و ‪ private‬قبالً توضیح دادیم‪ .‬در جدول زیر نحوه دسترسی به سه سطح ذکر شده نشان داده شده است ‪:‬‬

‫قابل دسترسی در ‪protected private public‬‬

‫‪true‬‬ ‫‪true‬‬ ‫‪true‬‬ ‫داخل کالس‬

‫‪false‬‬ ‫‪false‬‬ ‫‪true‬‬ ‫خارج از کالس‬

‫‪true‬‬ ‫‪false‬‬ ‫‪true‬‬ ‫کالس مشتق‬

‫مشاهده میکنید که ‪ public‬بیشترین سطح دسترسی را داراست‪ .‬صرف نظر از مکان‪ ،‬اعضای ‪ public‬در هر جا فراخوانی میشوند و قابل دسترسی هستند‪.‬‬
‫اعضای ‪ private‬فقط در داخل کالسی که به آن تعلق دارند قابل دسترسی هستند‪ .‬کد زیر رفتار اعضای دارای این سه سطح دسترسی را نشان میدهد ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class Parent‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;‪protected int protectedMember = 10‬‬
‫‪6:‬‬ ‫;‪private int privateMember = 10‬‬
‫‪7:‬‬ ‫;‪public int publicMember = 10‬‬
‫} ‪8:‬‬
‫‪9:‬‬
‫‪10: class Child : Parent‬‬
‫{ ‪11:‬‬
‫‪12:‬‬ ‫)(‪public Child‬‬
‫‪13:‬‬ ‫{‬
‫‪14:‬‬ ‫;‪protectedMember = 100‬‬

‫‪157‬‬
‫‪15:‬‬ ‫;‪privateMember = 100‬‬
‫‪16:‬‬ ‫;‪publicMember = 100‬‬
‫‪17:‬‬ ‫}‬
‫} ‪18:‬‬
‫‪19:‬‬
‫‪20: class Program‬‬
‫{ ‪21:‬‬
‫‪22:‬‬ ‫)(‪public static void Main‬‬
‫‪23:‬‬ ‫{‬
‫‪24:‬‬ ‫;)(‪Parent myParent = new Parent‬‬
‫‪25:‬‬
‫‪26:‬‬ ‫;‪myParent.protectedMember = 100‬‬
‫‪27:‬‬ ‫;‪myParent.privateMember = 100‬‬
‫‪28:‬‬ ‫;‪myParent.publicMember = 100‬‬
‫‪29:‬‬ ‫}‬
‫} ‪30:‬‬

‫کدهایی که با خط قرمز نشان داده شدهاند نشان دهنده وجود خطا هستند‪ ،‬چون فیلدهای ‪ protect‬و ‪ private‬در خارج از کالسی که به آن تعلق دارند‬
‫یعنی کالس ‪ ،Parent‬غیر قابل دسترسی هستند‪ .‬همانطور که در خط ‪ 15‬مشاهده میکنید کالس ‪ Child‬سعی میکند که به عضو ‪ private‬کالس‬
‫‪ Parent‬دسترسی یابد‪ .‬از آنجاییکه اعضای ‪ private‬در خارج از کالس قابل دسترسی نیستند‪ ،‬حتی کالس مشتق در خط ‪ 15‬نیز ایجاد خطا میکند‪ .‬اگر‬
‫شما به خط ‪ 14‬توجه کنید کالس ‪ Child‬میتواند به عضو ‪ protect‬کالس ‪ Parent‬دسترسی یابد چون کالس ‪ Child‬از کالس ‪ Parent‬مشتق‬
‫شده است‪ .‬حال به خط ‪ 26‬جاییکه میخواهیم در کالس ‪ Program‬به فیلد ‪ protect‬کالس ‪ Parent‬دسترسی یابیم نگاهی بیندازید‪ .‬میبینید که‬
‫برنامه پیغام خطا میدهد چون کالس ‪ Program‬از کالس ‪ Parent‬مشتق نشده است‪ .‬همچنین کالس ‪ Program‬به اعضای ‪ private‬کالس‬
‫‪ Parent‬نیز نمیتواند دسترسی یابد‪.‬‬

‫اعضای ‪Static‬‬

‫اگر بخواهیم عضو دادهای (فیلد) یا خاصیتی ایجاد کنیم که در همه نمونههای کالس قابل دسترسی باشد از کلمه کلیدی ‪ static‬استفاده میکنیم‪ .‬کلمه کلیدی‬
‫‪ static‬برای اعضای دادهای و خاصیتهایی به کار میرود که میخواهند در همه نمونههای کالس تقسیم شوند‪ .‬وقتی که یک متد یا خاصیت به صورت‬
‫‪ static‬تعریف شود‪ ،‬میتوانید آنها را بدون ساختن نمونهای از کالس‪ ،‬فراخوانی کنید‪ .‬به مثالی در مورد متدها و خاصیتهای ‪ static‬توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class SampleClass‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫} ;‪public static string StaticMessage { get; set‬‬
‫‪6:‬‬ ‫} ;‪public string NormalMessage { get; set‬‬
‫‪7:‬‬
‫‪8:‬‬ ‫)(‪public static void ShowStaticMessage‬‬
‫‪9:‬‬ ‫{‬
‫‪10:‬‬ ‫;)‪Console.WriteLine(StaticMessage‬‬
‫‪11:‬‬ ‫}‬
‫‪12:‬‬
‫‪13:‬‬ ‫)(‪public void ShowNormalMessage‬‬
‫‪14:‬‬ ‫{‬
‫‪15:‬‬ ‫;)‪Console.WriteLine(NormalMessage‬‬
‫‪16:‬‬ ‫}‬

‫‪158‬‬
‫‪17:‬‬
‫‪18:‬‬ ‫)(‪public void ShowStaticFromInstance‬‬
‫‪19:‬‬ ‫{‬
‫‪20:‬‬ ‫;)‪Console.WriteLine(StaticMessage‬‬
‫‪21:‬‬ ‫}‬
‫} ‪22:‬‬
‫‪23:‬‬
‫‪24: class Program‬‬
‫{ ‪25:‬‬
‫‪26:‬‬ ‫)(‪public static void Main‬‬
‫‪27:‬‬ ‫{‬
‫‪28:‬‬ ‫;)(‪SampleClass sample1 = new SampleClass‬‬
‫‪29:‬‬ ‫;)(‪SampleClass sample2 = new SampleClass‬‬
‫‪30:‬‬
‫‪31:‬‬ ‫;"!‪SampleClass.StaticMessage = "This is the static message‬‬
‫‪32:‬‬ ‫;)(‪SampleClass.ShowStaticMessage‬‬
‫‪33:‬‬
‫‪34:‬‬ ‫;"!‪sample1.NormalMessage = "nMessage from sample1‬‬
‫‪35:‬‬ ‫;)(‪sample1.ShowNormalMessage‬‬
‫‪36:‬‬ ‫;)(‪sample1.ShowStaticFromInstance‬‬
‫‪37:‬‬
‫‪38:‬‬ ‫;"!‪sample2.NormalMessage = "nMessage from sample2‬‬
‫‪39:‬‬ ‫;)(‪sample2.ShowNormalMessage‬‬
‫‪40:‬‬ ‫;)(‪sample2.ShowStaticFromInstance‬‬
‫‪41:‬‬ ‫}‬
‫} ‪42:‬‬

‫!‪This is the static message‬‬

‫!‪Message from sample1‬‬


‫!‪This is the static message‬‬

‫!‪Message from sample2‬‬


‫!‪This is the static message‬‬
‫در مثال باال یک خاصیت استاتیک به نام ‪( StaticMessage‬خط ‪ )5‬و یک متد استاتیک به نام )(‪( ShowStaticMessage‬خطوط ‪ )8-11‬تعریف‬
‫کردهایم‪ .‬مقدار خاصیت ‪ StaticMessage‬در همه نمونههای کالس ‪ SampleClass‬قابل دسترسی است‪ .‬متد استاتیک را نمیتوان به وسیله نمونه ایجاد‬
‫شده از کالس ‪ SampleClass‬فراخوانی کرد‪ .‬برای فراخوانی یک متد یا خاصیت استاتیک‪ ،‬به سادگی میتوان نام کالس و بعد از آن عالمت دات ( ‪ ) .‬و در‬
‫آخر نام متد یا خاصیت را نوشت‪ .‬این موضوع را میتوان در خطوط (‪ )31-32‬مشاهده کرد‪ .‬مشاهده میکنید که الزم نیست هیچ نمونهای از کالس ایجاد شود‪.‬‬
‫همانطور که مشاهده میکنید یک پیغام را به ‪ StaticMessage‬اختصاص دادهایم و با فراخوانی یک متد استاتیک ()(‪ )ShowStaticMessage‬مقدار آن‬
‫را نمایش میدهیم‪ .‬در مرحله بعد خاصیت ‪ NormalMessage‬را به وسیله دو نمونه ایجاد شده فراخوانی میکنیم و یک متد را هم برای نشان دادن مقدار آن‬
‫فراخوانی میکنیم‪ .‬همانطور که مشاهده میکنید نمونههای ایجاد شده دارای مقدار ‪ NormalMessage‬مخصوص خودشان هستند چون خاصیت‬
‫‪ NormalMessage‬غیر استاتیک است‪.‬‬
‫سپس )(‪ ShowStaticFromInstance‬فراخوانی میکنیم که متدی برای نشان دادن مقدار ‪ StaticMessage‬میباشد‪ .‬متدهای غیر استاتیک میتوانند‬
‫از فیلدها و خاصیت های استاتیک استفاده کنند ولی عکس این قضیه امکان پذیر نیست‪ .‬به عنوان مثال اگر شما یک متد ‪ static‬داشته باشید نمیتوانید از هر‬
‫خاصیت‪ ،‬متد‪ ،‬یا فیلدی که ‪ static‬نیست‪ ،‬استفاده کنید‪.‬‬

‫;‪private int number = 10‬‬

‫‪159‬‬
‫)(‪public static void ShowNumber‬‬
‫{‬
‫‪Console.WriteLine(number); //Error: cannot use non-static member‬‬
‫}‬

‫اصرار بر این کار باعث بروز خطا میشود‪ .‬به این نکته نیز توجه کنید که در سی شارپ‪ ،‬متد )(‪ Main‬باید به صورت ‪ static‬تعریف شود‪ .‬کامپایلر به‬
‫‪Static‬بودن متد )(‪ Main‬نیاز دارد تا بتواند برنامه را بدون ساختن نمونه اجرا کند‪.‬‬

‫کالس ‪Static‬‬

‫یک کالس ‪ static‬کالسی است که همه اعضای آن ‪ static‬باشند‪ .‬یکی از روشهای معمول استفاده از کالس ‪ ،static‬ایجاد یک کتابخانه ریاضی که شامل‬
‫تعدادی از توابع و مقادیر است‪ ،‬میباشد‪ .‬کالس ‪ Math‬یکی از این کالسها است که در درسهای آینده در مورد آن توضیح میدهیم‪ .‬موارد مهمی که در مورد‬
‫این کالسها باید بدانید عبارتند از ‪:‬‬

‫در تعریف کالس ‪ static‬باید از کلمه ‪ static‬استفاده شود‪.‬‬ ‫•‬


‫همه اعضای این کالسها باید ‪ static‬باشند‪.‬‬ ‫•‬
‫از کالس ‪ static‬نمیتوان نمونه (‪ )Object‬ایجاد کرد‪.‬‬ ‫•‬
‫کالسهای استاتیک به ضورت ضمنی ‪ sealed‬هستند‪ ،‬در نتیجه نمیتوان از آنها ارث بری کرد‪.‬‬ ‫•‬
‫این کالسها نمیتوانند سازنده یا ‪ constructor‬داشته باشند‪ ،‬ولی با این حال میتوان از ‪ static constructor‬ها برای مقدار دهی به عناصر‬ ‫•‬
‫‪ static‬کالس‪ ،‬استفاده کرد‪ .‬توجه کنید که ‪ static constructor‬ها پارامتر و سطح دسترسی ندارند‪.‬‬
‫برای دسترسی به اعضای ‪ static‬ای که در کالس هستند‪ ،‬کافی است ابتدا نام کالس را نوشته‪ ،‬سپس عملگر (‪ ).‬و در آخر نام عضو استاتیک را‬ ‫•‬
‫بنویسید‪.‬‬

‫به مثال زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: namespace StaticClass‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫‪public static class Person‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫)‪public static string ShowMessage(string message‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫;‪return message‬‬
‫‪10:‬‬ ‫}‬
‫‪11:‬‬ ‫}‬
‫‪12:‬‬
‫‪13:‬‬ ‫‪class Program‬‬
‫‪14:‬‬ ‫{‬
‫‪15:‬‬ ‫)‪static void Main(string[] args‬‬
‫‪16:‬‬ ‫{‬
‫‪17:‬‬ ‫;))"!‪Console.WriteLine(Person.ShowMessage("Hello World‬‬
‫‪18:‬‬ ‫}‬
‫‪19:‬‬ ‫}‬

‫‪160‬‬
‫} ‪20:‬‬

‫!‪Hello World‬‬
‫در کد باال یک کالس استاتیک به نام ‪ Person‬در خطوط ‪ 5-11‬تعریف شده است که دارای یک متد استاتیک با نام ()‪ ShowMessage‬میباشد‬
‫(خطوط ‪ .)7-10‬همانطور که در خط ‪ 17‬مشاهده میکنید برای دسترسی به این متد استاتیک‪ ،‬بدون اینکه از کالس شیء ایجاد کنیم‪ ،‬ابتدا نام کالس‬
‫سپس عالمت نقطه و در آخر نام متد را مینویسیم‪.‬‬

‫متدهای مجازی‬

‫متدهای مجازی متدهایی از کالس پایه هستند که میتوان به وسیله یک متد از کالس مشتق آنها را ‪ override‬کرده و به صورت دلخواه پیاده سازی نمود‪.‬‬
‫به عنوان مثال شما متد ‪ A‬را در کالس ‪ A‬دارید و کالس ‪ B‬از کالس ‪ A‬ارث بری میکند‪ ،‬در این صورت متد ‪ A‬در کالس ‪ B‬در دسترس خواهد بود‪ .‬اما متد‬
‫‪ A‬دقیق همان متدی است که از کالس ‪ A‬به ارث برده شده است‪ .‬حال اگر بخواهید که این متد رفتار متفاوتی از خود نشان دهد چکار میکنید؟ متد مجازی این‬
‫مشکل را برطرف میکند‪ .‬به تکه کد زیر توجه کنید‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class Parent‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public virtual void ShowMessage‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;)"‪Console.WriteLine("Message from Parent.‬‬
‫‪8:‬‬ ‫}‬
‫} ‪9:‬‬
‫‪10:‬‬
‫‪11: class Child : Parent‬‬
‫{ ‪12:‬‬
‫‪13:‬‬ ‫)(‪public override void ShowMessage‬‬
‫‪14:‬‬ ‫{‬
‫‪15:‬‬ ‫;)"‪Console.WriteLine("Message from Child.‬‬
‫‪16:‬‬ ‫}‬
‫} ‪17:‬‬
‫‪18:‬‬
‫‪19: class Program‬‬
‫{ ‪20:‬‬
‫‪21:‬‬ ‫)(‪public static void Main‬‬
‫‪22:‬‬ ‫{‬
‫‪23:‬‬ ‫;)(‪Parent myParent = new Parent‬‬
‫‪24:‬‬ ‫;)(‪Child myChild = new Child‬‬
‫‪25:‬‬
‫‪26:‬‬ ‫;)(‪myParent.ShowMessage‬‬
‫‪27:‬‬ ‫;)(‪myChild.ShowMessage‬‬
‫‪28:‬‬ ‫}‬
‫} ‪29:‬‬

‫‪Message from Parent.‬‬


‫‪Message from Child.‬‬

‫‪161‬‬
‫متد مجازی با قرار دادن کلمه کلیدی ‪ virtual‬هنگام تعریف متد‪ ،‬تعریف میشود‪( .‬خط ‪ )5‬این کلمه کلیدی نشان میدهد که متد میتواند ‪ override‬شود یا‬
‫به عبارت دیگر میتواند به صورت دیگر پیاده سازی شود‪ .‬کالسی که از کالس ‪ Parent‬ارث میبرد شامل متدی است که متد مجازی کالس پایه را‬
‫‪ override‬یا به صورت دیگری پیاده سازی میکند‪ .‬با استفاده از کلمه کلیدی ‪ override‬میتوان متد مجازی کالس پایه را به صورت دیگر پیاده سازی کرد‪.‬‬
‫با استفاده از کلمه کلیدی ‪( base‬خط ‪ )17‬میتوانید متد مجازی را در داخل متد ‪ override‬شده فراخوانی کنید‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class Parent‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;"‪private string name = "Parent‬‬
‫‪6:‬‬
‫‪7:‬‬ ‫)(‪public virtual void ShowMessage‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫;)"‪Console.WriteLine("Message from Parent.‬‬
‫‪10:‬‬ ‫}‬
‫} ‪11:‬‬
‫‪12:‬‬
‫‪13: class Child : Parent‬‬
‫{ ‪14:‬‬
‫‪15:‬‬ ‫)(‪public override void ShowMessage‬‬
‫‪16:‬‬ ‫{‬
‫‪17:‬‬ ‫;)(‪base.ShowMessage‬‬
‫‪18:‬‬ ‫;)"‪Console.WriteLine("Message from Child.‬‬
‫‪19:‬‬ ‫}‬
‫} ‪20:‬‬
‫‪21:‬‬
‫‪22: class Program‬‬
‫{ ‪23:‬‬
‫‪24:‬‬ ‫)(‪public static void Main‬‬
‫‪25:‬‬ ‫{‬
‫‪26:‬‬ ‫;)(‪Parent myParent = new Parent‬‬
‫‪27:‬‬ ‫;)(‪Child myChild = new Child‬‬
‫‪28:‬‬
‫‪29:‬‬ ‫;)(‪myParent.ShowMessage‬‬
‫‪30:‬‬ ‫;)(‪myChild.ShowMessage‬‬
‫‪31:‬‬ ‫}‬
‫} ‪32:‬‬

‫‪Message from Parent.‬‬


‫‪Message from Parent.‬‬
‫‪Message from Child.‬‬
‫اگر بخواهید از متد پایه استفاده کنید و هیچ کدی داخل متد ‪ override‬نباشد (مثالً فرض کنید خط ‪ 18‬در مثال باال وجود نداشته باشد)‪ ،‬بسیار شبیه به این است‬
‫که از هیچ متد ‪ override‬ی استفاده نکردهاید‪.‬‬

‫نمیتوان متد غیر ‪ virtual‬و یا یک متد ‪ static‬را ‪ override‬کرد‪.‬‬ ‫•‬


‫متد ‪ override‬نیز باید دارای سطح دسترسی شبیه به متد مجازی باشد‪.‬‬ ‫•‬

‫‪162‬‬
‫میتوان یک کالس دیگر که از کالس ‪ Child‬ارث بری میکند ایجاد کرده و دوباره متد )(‪ ShowMessage‬را ‪ override‬کرده و آنرا به صورت دیگر‬
‫پیاده سازی کنیم‪ .‬اگر بخواهید متدی را که ایجاد کردهاید به وسیله سایر کالسها ‪ override‬نشود کافیست که از کلمه کلیدی ‪ sealed‬به صورت زیر استفاده‬
‫کنید ‪:‬‬

‫)(‪public sealed override void ShowMessage‬‬

‫حال اگر کالس دیگری از کالس ‪ Child‬ارث ببرد نمیتواند متد )(‪ ShowMessage‬را ‪ override‬کند‪ .‬به یک مثال دیگر توجه کنید‪ .‬فرض کنید‬
‫میخواهیم متد )(‪ ToString‬کالس ‪ System.Object‬را ‪ override‬کنیم‪ .‬همانطور که در درس آینده خواهید دید همه کالسها در سی شارپ از کالس‬
‫‪ Object‬ارث میبرند‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class Person‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫} ;‪public string FirstName { get; set‬‬
‫‪6:‬‬ ‫} ;‪public string LastName { get; set‬‬
‫‪7:‬‬
‫‪8:‬‬ ‫)(‪public override string ToString‬‬
‫‪9:‬‬ ‫{‬
‫‪10:‬‬ ‫;‪return FirstName + " " + LastName‬‬
‫‪11:‬‬ ‫}‬
‫} ‪12:‬‬
‫‪13:‬‬
‫‪14: class Program‬‬
‫{ ‪15:‬‬
‫‪16:‬‬ ‫)(‪public static void Main‬‬
‫‪17:‬‬ ‫{‬
‫‪18:‬‬ ‫;)(‪Person person1 = new Person‬‬
‫‪19:‬‬
‫‪20:‬‬ ‫;"‪person1.FirstName = "John‬‬
‫‪21:‬‬ ‫;"‪person1.LastName = "Smith‬‬
‫‪22:‬‬
‫‪23:‬‬ ‫;))(‪Console.WriteLine(person1.ToString‬‬
‫‪24:‬‬ ‫}‬
‫} ‪25:‬‬

‫‪John Smith‬‬
‫از آنجاییکه متد )(‪ ToString‬کالس ‪ System.Object‬را ‪ override‬کردهایم‪ ،‬به جای چاپ نوع شیء پیشفرض‪ ،‬خروجی ما سفارشی شده و نام و‬
‫نام خانوادگی نمایش داده میشود‪.‬‬

‫کالس آبجکت(‪)System.Object Class‬‬

‫همه کالسهای دات نت از کالس آبجکت (‪ )System.Object‬ارث میبرند‪ .‬کالس آبجکت در سی شارپ با کلمه کلیدی ‪ object‬نشان داده میشود‪ .‬برای‬
‫راحتی در این درس از کلمه آبجکت به جای ‪ System.Object‬استفاده میکنیم‪ .‬در زیر لیست برخی از متدهای معمول در کالس آبجکت آمده است ‪:‬‬

‫‪Static‬‬ ‫‪Virtual‬‬ ‫نوع برگشتی‬ ‫متد‬

‫‪163‬‬
‫‪Static‬‬ ‫‪Virtual‬‬ ‫نوع برگشتی‬ ‫متد‬

‫‪No‬‬ ‫‪No‬‬ ‫‪None‬‬ ‫)(‪Object‬‬

‫‪No‬‬ ‫‪No‬‬ ‫‪None‬‬ ‫)(‪~Object‬‬

‫‪No‬‬ ‫‪Yess‬‬ ‫‪bool‬‬ ‫)‪Equals(object‬‬

‫‪Yes‬‬ ‫‪No‬‬ ‫‪bool‬‬ ‫)‪Equals(object, object‬‬

‫‪ReferenceEquals‬‬
‫‪Yes‬‬ ‫‪No‬‬ ‫‪bool‬‬
‫)‪(object,object‬‬

‫‪No‬‬ ‫‪Yes‬‬ ‫‪string‬‬ ‫)(‪ToString‬‬

‫‪No‬‬ ‫‪No‬‬ ‫‪object‬‬ ‫)(‪MemberwiseClone‬‬

‫‪No‬‬ ‫‪No‬‬ ‫‪System.Type‬‬ ‫)(‪GetType‬‬

‫‪No‬‬ ‫‪Yes‬‬ ‫‪int‬‬ ‫)(‪GetHashCode‬‬

‫همه متدهای این کالس معموالً مورد استفاده قرار نمیگیرند‪ .‬از آنجاییکه همه کالسهای سی شارپ از این کالس ارث میبرند‪ ،‬آنها نیز دارای این متدها به جز‬
‫متدهای ‪ Static‬میباشند‪ .‬وقتی یک کالس ایجاد میکنید‪ ،‬این کالس به صورت ضمنی از کالس آبجکت ارث میبرد‪ .‬بنابراین وقتی یک کالس تعریف‬
‫میکنید کدها در حقیقت به صورت زیر به وسیله کامپایلر خوانده میشوند ‪:‬‬

‫‪class MyClass : System.Object‬‬


‫{‬
‫}‬

‫اینکه چرا همه کالسها در دات نت از ‪ object‬ارث بری میکنند به دلیل امکان استفاده از چندریختی است که در درس آینده درباره آن توضیح میدهیم‪ .‬به‬
‫عنوان مثال یکی از سربارگذاری های متد )(‪ Console.WriteLine‬قبول نوع آبجکت به عنوان آرگومان است‪ .‬به همین دلیل است که شما میتوانید تقریباً‬
‫هر چیز را به عنوان آرگومان به متد )(‪ Console.WriteLine‬ارسال کنید‪ .‬برای نشان دادن اینکه هر چیز در سی شارپ یک شیء است به مثال ساده زیر‬
‫توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪int myInt = 1‬‬
‫‪8:‬‬ ‫;‪double myDouble = 4.0‬‬
‫‪9:‬‬ ‫;"‪string myString = "Hello‬‬
‫‪10:‬‬
‫‪11:‬‬ ‫;))(‪Console.WriteLine(myInt.ToString‬‬
‫‪12:‬‬ ‫;))(‪Console.WriteLine(myDouble.ToString‬‬
‫‪13:‬‬ ‫;))(‪Console.WriteLine(myString.ToString‬‬
‫‪14:‬‬ ‫}‬

‫‪164‬‬
‫} ‪15:‬‬

‫همانطور که مشاهده میکنید اشیاء ‪ double، int‬و ‪ string‬همگی متد )(‪ ToString‬را فراخوانی میکنند که این متد از کالس ‪ object‬به ارث برده‬
‫شده است‪.‬‬

‫‪ Boxing‬و ‪Unboxing‬‬

‫‪ Boxing‬فرایندی است که طی آن یک نوع مقداری مانند ساختار (‪ )Struct‬به یک نوع مرجع مانند یک شیء (‪ )Object‬تبدیل میشود‪Unboxing .‬‬
‫برعکس‪ ،‬عمل تبدیل یک نوع مرجع به یک نوع مقداری میباشد‪ .‬کد زیر فرایند ‪ boxing‬را نشان میدهد‪.‬‬

‫‪1: struct MyStruct‬‬


‫{ ‪2:‬‬
‫‪3:‬‬ ‫} ;‪public int Number { get; set‬‬
‫} ‪4:‬‬
‫‪5:‬‬
‫‪6: class Program‬‬
‫{ ‪7:‬‬
‫‪8:‬‬ ‫)(‪public static void Main‬‬
‫‪9:‬‬ ‫{‬
‫‪10:‬‬ ‫;)(‪MyStruct valueType = new MyStruct‬‬
‫‪11:‬‬ ‫;‪valueType.Number = 10‬‬
‫‪12:‬‬ ‫;‪object refType = valueType‬‬
‫‪13:‬‬ ‫}‬
‫} ‪14:‬‬

‫در کد باال یک ساختار به نام ‪ MyStruct‬ایجاد کردهایم و یک خاصیت (‪ )property‬برای تست اهداف برای آن در نظر گرفتهایم‪ .‬در فرایند ‪ boxing‬نوع‬
‫مقداری به سادگی با یک متغیر از نوع آبجکت برابر قرار داده میشود‪ .‬در کد باال ‪ refType‬شامل آدرس یک نوع ‪ MyStruct‬است نه آدرس اصلی متغیر‬
‫‪ .valueType‬در زیر نحوه تبدیل ‪ refType‬به نوع مقداری ‪ MyStruct‬به وسیله ‪ unboxing‬نشان داده شده است‪.‬‬

‫;‪MyStruct valueType2 = (MyStruct)refType‬‬

‫همانطور که مشاهده میکنید با استفاده از تبدیل صریح متغیر نوع مرجع ‪ refType‬را به متغیر نوع مقدار ‪ MyStruct‬تبدیل کردهایم‪.‬‬

‫ترکیب (‪)Containment‬‬

‫محدود نگه داشتن یا ترکیب فرایندی است که طی آن یک کالس به عنوان یک عضو به کالس دیگر اضافه میشود‪ .‬به عنوان مثال کالس ‪ Person‬میتواند‬
‫یک فیلد از نوع کالس ‪ Name‬داشته باشد‪ .‬به کد زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class Name‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫} ;‪public string FirstName { get; set‬‬
‫‪6:‬‬ ‫} ;‪public string LastName { get; set‬‬
‫‪7:‬‬
‫‪8:‬‬ ‫)‪public Name(string f, string l‬‬
‫‪9:‬‬ ‫{‬
‫‪165‬‬
10: FirstName = f;
11: LastName = l;
12: }
13: }
14:
15: class Person
16: {
17: private Name myName;
18:
19: public Name MyName
20: {
21: get { return myName; }
22: set { myName = value; }
23: }
24:
25: public Person(Name name)
26: {
27: myName = new Name(name.FirstName, name.LastName);
28: }
29:
30: public override string ToString()
31: {
32: return myName.FirstName + " " + myName.LastName;
33: }
34: }
35:
36: class Program
37: {
38: public static void Main()
39: {
40: Person person1 = new Person(new Name("John", "Smith"));
41:
42: Console.WriteLine(person1.ToString());
43: }
44: }

John Smith
: ‫حال برنامه را به صورت بخش بخش توضیح میدهیم‬

class Name
{
public string FirstName { get; set; }
public string LastName { get; set; }

public Name(string f, string l)


{
FirstName = f;
LastName = l;
}
}

166
‫یک کالس که قرار است به عنوان یک فیلد در کالس دیگر به کار رود را تعریف میکنیم (خط ‪ .)17‬این کالس‪ ،‬دارای یک سازنده است که نام (‪ )f‬و نام‬
‫خانوادگی (‪ )l‬را از شخص دریافت میکند‪ .‬سپس این مقادیر را در خصوصیتهای متناظر با آنها قرار میدهیم (خطوط ‪.)5-12‬‬

‫‪class Person‬‬
‫{‬
‫;‪private Name myName‬‬

‫‪public Name MyName‬‬


‫{‬
‫} ;‪get { return myName‬‬
‫} ;‪set { myName = value‬‬
‫}‬

‫)‪public Person(Name name‬‬


‫{‬
‫;)‪myName = new Name(name.FirstName, name.LastName‬‬
‫}‬

‫)(‪public override string ToString‬‬


‫{‬
‫;‪return myName.FirstName + " " + myName.LastName‬‬
‫}‬
‫}‬

‫این کالس شامل یک فیلد از نوع ‪ Name‬و خاصیت متناضر با آن است‪ .‬این خصوصیت مقدار نام هر شی ‪ Person‬را در خود نگهداری میکند‪ .‬به این نکته‬
‫توجه کنید که سازنده یک شیء ‪ Name‬را میپذیرد و سپس با استفاده از این شیء فیلد ‪ myName‬را مقداردهی میکند‪ .‬به این فرایند ترکیب‬
‫گویند‪.‬‬ ‫می‬ ‫(‪)aggregation‬‬
‫همچنین در کالس ‪ Person‬متد )(‪ ToString‬از کالس ‪ System.Object‬را بازنویسی (‪ )override‬میکنیم به طوری که در هنگام فراخوانی نام کامل‬
‫شخص را نمایش دهد‪.‬‬

‫‪class Program‬‬
‫{‬
‫)(‪public static void Main‬‬
‫{‬
‫;))"‪Person person1 = new Person(new Name("John", "Smith‬‬

‫;))(‪Console.WriteLine(person1.ToString‬‬
‫}‬
‫}‬

‫در باال یکشی ‪ Person‬را ایجاد و از سازندهای که یک شیء از نوع کالس ‪ Name‬به عنوان آرگومان قبول میکند استفاده کردهایم‪ .‬این شیء را مستقیماً در‬
‫داخل پرانتزها تعریف و همچنین مقادیر خصوصیات ‪ firstname‬و ‪ lastname‬را به آن ارسال کردهایم‪ .‬در نهایت‪ ،‬با استفاده از متد سفارشی )(‪ToString‬‬
‫نتیجه را چاپ میکنیم‪ .‬به این نکته توجه کنید که کالسها می توانند اشیایی از نوع خود کالس داشته باشند‪ .‬به عنوان نمونه کالس ‪ Person‬میتواند یک‬
‫عضو با نوع ‪ Person‬داشته باشد‪ .‬به کد زیر توجه نمایید ‪:‬‬

‫‪class Person‬‬
‫{‬
‫} ;‪public Person Sibling { get; set‬‬
‫} ;‪public string Name { get; set‬‬

‫‪167‬‬
‫}‬

‫مشاهده میکنید که چگونه خصوصیتی از نوع ‪ Person‬در داخل کالس ‪ Person‬تعریف شده است‪ .‬پس هنگامی که یک شیء ‪ Person‬تعریف میکنید‪،‬‬
‫شیء ایجاد شده یک شیء از نوع ‪ Person‬در داخل خود دارد‪.‬‬

‫;)(‪Person person1 = new Person‬‬


‫;)(‪person1.Sibling = new Person‬‬
‫;"‪person1.Name = "John Smith‬‬
‫;"‪person1.Sibling.Name = "Mike Smith‬‬

‫کد باال چگونگی دسترسی و مقدار دهی به عضو ‪ (Sibling)Person‬را نشان داده است‪ .‬از آنجایی که خصوصیت ‪ Sibling‬از نوع ‪ Person‬است پس‬
‫میتواند یک شیء ‪ Person‬در داخل خود داشته باشد‪ .‬بنابراین میتوان هر تعداد ‪ sibling‬که میخواهید در داخل شیء ‪ person1‬داشته باشید ‪:‬‬

‫;)(‪person1.Sibling.Sibling = new Person‬‬


‫;"‪person1.Sibling.Sibling.Name = "Franc Smith‬‬
‫;)(‪person1.Sibling.Sibling.Sibling = new Person‬‬
‫;"‪person1.Sibling.Sibling.Sibling.Name = "Bob Smith‬‬
‫‪//And so on...‬‬

‫سربارگذاری عملگرها‬

‫سربارگذاری عملگرها به شما اجازه می دهد که رفتار عملگرهای سی شارپ را بسته به نوع عملوندهای آنها سفارشی کنید‪ .‬سربارگذاری عملگرها همچنین به‬
‫عملگر اجازه میدهد که یک شیء را به روشی دیگر ترجمه کند‪ .‬به کد زیر توجه کنید ‪:‬‬

‫‪1: class MyNumber‬‬


‫{ ‪2:‬‬
‫‪3:‬‬ ‫} ;‪public int Number { get; set‬‬
‫} ‪4:‬‬
‫‪5:‬‬
‫‪6: class Program‬‬
‫{ ‪7:‬‬
‫‪8:‬‬ ‫)(‪public static void Main‬‬
‫‪9:‬‬ ‫{‬
‫‪10:‬‬ ‫;)(‪MyNumber firstNumber = new MyNumber‬‬
‫‪11:‬‬ ‫;)(‪MyNumber secondNumber = new MyNumber‬‬
‫‪12:‬‬
‫‪13:‬‬ ‫;‪firstNumber.Number = 10‬‬
‫‪14:‬‬ ‫;‪secondNumber.Number = 5‬‬
‫‪15:‬‬
‫‪16:‬‬ ‫;‪MyNumber sum = firstNumber + secondNumber‬‬
‫‪17:‬‬ ‫}‬
‫} ‪18:‬‬

‫خط پررنگ شده در کد باال (خط ‪ )18‬کد قابل قبولی نیست چون‪ ،‬کامپایلر نمیتواند دو شیء را با هم جمع کند‪ .‬رفتاری که ما از کد باال انتظار داریم اضافه کردن‬
‫مقادیر به خاصیت ‪ Number‬دو عملوند و سپس ایجاد یک شیء جدید که حاصل جمع دو مقدار در داخل آن قرار بگیرد‪ .‬سپس این شیء جدید به متغیر ‪sum‬‬
‫تخصیص داده شود‪.‬‬

‫‪168‬‬
‫سر بارگذاری عملگرهای دوتایی‬

‫برنامه را برای اضافه کردن سربارگذاری یک عملگر دوتایی (‪ )+‬که دو عملوند قبول میکند تغییر میدهیم‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class MyNumber‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫} ;‪public int Number { get; set‬‬
‫‪6:‬‬
‫‪7:‬‬ ‫)‪public static MyNumber operator +(MyNumber n1, MyNumber n2‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫;)(‪MyNumber result = new MyNumber‬‬
‫‪10:‬‬ ‫;‪result.Number = n1.Number + n2.Number‬‬
‫‪11:‬‬ ‫;‪return result‬‬
‫‪12:‬‬ ‫}‬
‫} ‪13:‬‬
‫‪14:‬‬
‫‪15: class Program‬‬
‫{ ‪16:‬‬
‫‪17:‬‬ ‫)(‪public static void Main‬‬
‫‪18:‬‬ ‫{‬
‫‪19:‬‬ ‫;)(‪MyNumber firstNumber = new MyNumber‬‬
‫‪20:‬‬ ‫;)(‪MyNumber secondNumber = new MyNumber‬‬
‫‪21:‬‬
‫‪22:‬‬ ‫;‪firstNumber.Number = 10‬‬
‫‪23:‬‬ ‫;‪secondNumber.Number = 5‬‬
‫‪24:‬‬
‫‪25:‬‬ ‫;‪MyNumber sum = firstNumber + secondNumber‬‬
‫‪26:‬‬
‫‪27:‬‬ ‫;)‪Console.WriteLine("Sum = {0}", sum.Number‬‬
‫‪28:‬‬ ‫}‬
‫} ‪29:‬‬

‫‪Sum = 15‬‬
‫برای سربارگذاری عملگرها به صورت زیر عمل کنید ‪:‬‬

‫)‪public static returnType operator operatorSymbol(type operand1, type operand2‬‬


‫{‬
‫‪//Codes here‬‬
‫;‪return result‬‬
‫}‬

‫همانطور که مشاهده میکنید در سربارگذاری عملگرها از یک متد که هم ‪ static‬و هم ‪ public‬باشد استفاده میشود‪ .‬این متد باید ‪ static‬باشد چون همه‬
‫نمونههای کالس از آن استفاده میکنند و هم باید ‪ public‬باشد تا بتوان در خارج از کالس از آن استفاده کرد‪ .‬سپس از کلمه کلیدی ‪ operator‬و بعد از آن از‬
‫میکنیم‪.‬‬ ‫استفاده‬ ‫–‬ ‫یا‬ ‫‪+‬‬ ‫مانند‬ ‫عملگر‬ ‫یک‬ ‫عالمت‬
‫در س ربارگذاری یک عملگر دوتایی به دو عملوند نیاز است‪ ،‬بنابراین متد دارای دو پارامتر است که این دو عملوند را قبول میکند‪ .‬در داخل کد یک شیء ایجاد‬
‫شده است که نتیجه را در خود نگداری میکند‪ .‬دو خاصیت ‪ Number‬برای دو پارامتر اضافه کرده و حاصل جمع این دو را در خاصیت ‪ Number‬شی‬
‫‪( result‬که نتیجه را در خود ذخیره میکند) قرار میدهیم (خط ‪ .)12‬و در آخر نتیجه را به فراخوان بازگشت میدهیم (خط ‪ .)13‬شیء ‪ result‬به متغیر ‪sum‬‬

‫‪169‬‬
‫است‪.‬‬ ‫شده‬ ‫داده‬ ‫ارجاع‬
‫همه عملگرها نمیتوانند سر بارگذاری شوند‪ .‬مثالً شما نمیتوانید عملگر =‪ +‬را سربارگذاری کنید‪ .‬شما میتوانید عملگر ‪ +‬را سربارگذاری کنید که در این صورت‬
‫عملگر ‪ =+‬به صورت خودکار سربارگذاری میشود‪ .‬عملگرهای > یا < باید به صورت جفت سربارگذاری شوند‪ .‬مثالً نمیتوان عملگر > را به تنهایی سربارگذاری‬
‫کنید‪.‬‬

‫)‪public static bool operator >(MyNumber n1, MyNumber n2‬‬


‫{‬
‫;)‪return (n1.Number > n2.Number‬‬
‫}‬

‫)‪public static bool operator <(MyNumber n1, MyNumber n2‬‬


‫{‬
‫;)‪return (n1.Number < n2.Number‬‬
‫}‬

‫سربارگذاری عملگرهای یگانی‬

‫سربارگذاری عملگر یگانی بسیار ساده است‪ .‬همه کاری که شما باید انجام دهید تهیه یک پارامتر است چون عملگر یگانی ‪ 1‬عملوند قبول میکند‪ .‬به عنوان مثال‪،‬‬
‫اجازه دهید که عملگر یگانی ‪ ++‬را سربارگذاری کنیم‪.‬‬

‫)‪public static MyNumber operator ++(MyNumber n1‬‬


‫{‬
‫;)(‪MyNumber result = new MyNumber‬‬
‫;‪result.Number = n1.Number + 1‬‬
‫;‪return result‬‬
‫}‬

‫همانطور که می بینید سربارگذاری عملگرهای یگانی شبیه به سربارگذاری عملگرهای دوتایی است‪ .‬در سربارگذاری عملگرها به نکات زیر توجه کنید ‪:‬‬

‫نمیتوانید یک عملگر جدید ایجاد کنید‪.‬‬ ‫•‬


‫دستور زبان یک عملگر را تغییر دهید‪.‬‬ ‫•‬
‫عملکرد یک عملگر را نمیتوان دوباره تعریف کرد‪.‬‬ ‫•‬
‫نمیتوان تقدم یک عملگر را عوض کرد‪.‬‬ ‫•‬

‫است‪.‬‬ ‫آمده‬ ‫زیر‬ ‫در‬ ‫دارند‪،‬‬ ‫را‬ ‫سربارگذاری‬ ‫قابلیت‬ ‫که‬ ‫عملگرهایی‬ ‫لیست‬
‫عملگرهای دوتایی ‪:‬‬

‫=< ‪+, -, *, /, %, &, |, ^, <<, >>, ==, !=, >, <, >=,‬‬

‫عملگرهای یگانی‬
‫‪+, -, !, ~, ++, --, true, false‬‬

‫عملگر ‪is‬‬

‫‪170‬‬
‫عملگر ‪ is‬در سی شارپ به شما اجازه میدهد که تست کنید که آیا یک شیء میتواند به طور کامل به وسیله تبدیل صریح به شیء دیگری تبدیل شود‪ .‬عملگر‬
‫‪ is‬به دو عملوند نیاز دارد و یک مقدار بولی را برمی گرداند‪ .‬به عنوان مثال‪ ،‬فرض کنید یک کالس به نام ‪ Animel‬داریم‪ ،‬سپس یک نمونه از آن ایجاد‬
‫میکنیم ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class Animal‬‬
‫{ ‪4:‬‬
‫‪5:‬‬
‫} ‪6:‬‬
‫‪7:‬‬
‫‪8: class Program‬‬
‫{ ‪9:‬‬
‫‪10:‬‬ ‫)(‪public static void Main‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫;)(‪Animal myAnimal = new Animal‬‬
‫‪13:‬‬
‫‪14:‬‬ ‫)‪if (myAnimal is Animal‬‬
‫‪15:‬‬ ‫{‬
‫‪16:‬‬ ‫;)"!‪Console.WriteLine("myAnimal is an Animal‬‬
‫‪17:‬‬ ‫}‬
‫‪18:‬‬ ‫}‬
‫} ‪19:‬‬

‫‪myAnimal is an Animal‬‬
‫رفتار عملگر ‪ is‬را در این مثال مشاهده کردید‪ .‬همانطور که میبینید از آن به عنوان شرط در عبارت ‪ if‬استفاده شده است‪ .‬کاربرد آن در مثال باال این است که‬
‫چک میکند که آیا شیء ‪ myAnimal‬یک نمونه از ‪ Animal‬است و چون نتیجه درست است کدهای داخل دستور ‪ if‬اجرا میشود‪ .‬این عملگر همچنین‬
‫می تواند چک کند که آیا یک شیء خاص در سلسله مراتب وراثت یک نوع خاص است‪ .‬به این مثال توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class Animal‬‬
‫{ ‪4:‬‬
‫‪5:‬‬
‫} ‪6:‬‬
‫‪7:‬‬
‫‪8: class Dog : Animal‬‬
‫{ ‪9:‬‬
‫‪10:‬‬
‫} ‪11:‬‬
‫‪12:‬‬
‫‪13: class Program‬‬
‫{ ‪14:‬‬
‫‪15:‬‬ ‫)(‪public static void Main‬‬
‫‪16:‬‬ ‫{‬
‫‪17:‬‬ ‫;)(‪Dog myDog = new Dog‬‬
‫‪18:‬‬
‫‪19:‬‬ ‫)‪if (myDog is Animal‬‬
‫‪20:‬‬ ‫{‬
‫‪21:‬‬ ‫;)"!‪Console.WriteLine("myDog is an Animal‬‬
‫‪22:‬‬ ‫}‬
‫‪171‬‬
‫‪23:‬‬ ‫}‬
‫} ‪24:‬‬

‫!‪myDog is an Animal‬‬
‫همانطور که در مثال باال میبینید ما یک کالس به نام ‪ Dog‬ایجاد کردهایم که از کالس ‪ Animal‬ارث میبرد‪ .‬سپس یک نمونه از این کالس (‪ )Dog‬ایجاد‬
‫میکنیم و سپس با استفاده از عملگر ‪ is‬تست میکنیم که آیا نمونه ایجاد شده جز کالس ‪ Animal‬است یا یک کالس مشتق شده از کالس ‪Animal‬‬
‫میباشد‪ .‬از آنجاییکه کالس ‪ Dog‬از کالس ‪ Animal‬ارث میبرد (سگ من یک حیوان است‪ ،).‬نتیجه عبارت درست (‪ )true‬است‪ .‬حال جمله باال را تغییر‬
‫دهیم‪ ” :‬حیوان من یک سگ است”‪ .‬وقتی جمله برعکس میشود چه اتفاقی می افتد؟‬

‫;)(‪Animal myAnimal = new Animal‬‬

‫)‪if (myAnimal is Dog‬‬


‫{‬
‫;)"!‪Console.WriteLine("myAnimal is a Dog‬‬
‫}‬

‫این باعث خطا نمیشود و عبارت فقط نتیجه ‪ false‬را بر میگرداند‪ .‬میتوان از کد باال این را درک کرد که همه حیوانات سگ نیستند ولی همه سگها حیوان‬
‫هستند‪ .‬راه دیگر برای چک کردن نوع یک شیء (‪ )object‬استفاده از عملگر ‪ typeof‬و متد )(‪ GetType‬کالس ‪ System.object‬است‪.‬‬

‫))‪if (myAnimal.GetType() == typeof(Animal‬‬


‫{‬
‫}‬

‫متد )(‪ GetType‬یک شیء از نوع ‪ System.Type‬را بر میگرداند که نشان دهنده نوع شیئی که آن را فراخوانی کرده است‪ ،‬میباشد‪ .‬عملگر ‪ typeof‬نام‬
‫یک نوع را قبول کرده و شیء ‪ System.Type‬متناظر با آن را بر میگرداند‪.‬‬

‫رابط ها (‪)Interfaces‬‬

‫رابطها یا اینترفیس ها شبیه به کالسها هستند اما فقط شامل تعاریفی برای متدها و خواص (‪ )Property‬میباشند‪ .‬رابطها را میتوان به عنوان پالگین های‬
‫کالسها در نظر گرفت‪ .‬کالسی که یک رابط خاص را پیاده سازی می کند الزم است که کدهایی برای اجرا توسط اعضا و متدهای آن فراهم کند چون اعضا و‬
‫متدهای رابط هیچ کد اجرایی در بدنه خود ندارند‪ .‬اجازه دهید که نحوه تعریف و استفاده از یک رابط در کالس را توضیح دهیم ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: interface ISample‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;)‪void ShowMessage(string message‬‬
‫} ‪6:‬‬
‫‪7:‬‬
‫‪8: public class Sample : ISample‬‬
‫{ ‪9:‬‬
‫‪10:‬‬ ‫)‪public void ShowMessage(string message‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫;)‪Console.WriteLine(message‬‬
‫‪13:‬‬ ‫}‬
‫} ‪14:‬‬
‫‪15:‬‬
‫‪16: class Program‬‬

‫‪172‬‬
‫{ ‪17:‬‬
‫‪18:‬‬ ‫)(‪public static void Main‬‬
‫‪19:‬‬ ‫{‬
‫‪20:‬‬ ‫;)(‪Sample sample = new Sample‬‬
‫‪21:‬‬
‫‪22:‬‬ ‫;)"!‪sample.ShowMessage("Implemented the ISample Interface‬‬
‫‪23:‬‬ ‫}‬
‫} ‪24:‬‬

‫!‪Implemented the ISample Interface‬‬


‫در خطوط ‪ 3-6‬یک رابط به نام ‪ ISample‬تعریف کردهایم‪ .‬بر طبق قراردادهای نامگذاری‪ ،‬رابطها به شیوه پاسکال نامگذاری میشوند و همه آنها باید با حرف‬
‫‪ I‬شروع شوند‪ .‬یک متد در داخل بدنه رابط تعریف میکنیم (خط ‪ .) 5‬به این نکته توجه کنید که متد تعریف شده فاقد بدنه است و در آخران باید از سیمیکولن‬
‫شود‪.‬‬ ‫استفاده‬
‫وقتی که متد را در داخل رابط تعریف می کنید فقط الزم است که عنوان متد (نوع‪ ،‬نام و پارامترهای آن) را بنویسید‪ .‬به این نکته نیز توجه کنید که متدها و خواص‬
‫تعریف شده در داخل رابط سطح دسترسی ندارند چون باید همیشه هنگام اجرای کالسها در دسترس باشند‪ .‬وقتی یک کالس نیاز به اجرای یک رابط داشته باشد‪،‬‬
‫از همان روشی که در وراثت استفاده میکردیم‪ ،‬استفاده میکنیم‪ .‬کالسی که رابط را اجرا میکند کدهای واقعی را برای اعضای آن فراهم میکند‪ .‬همانطور که در‬
‫مثال باال میبینید کالس ‪ ، Sample‬متد )(‪ ShowMessage‬رابط ‪ ISample‬را اجرا و تغذیه میکند‪.‬‬
‫برای روشن شدن کاربرد رابطها به مثال زیر توجه کنید‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class CA‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;‪public string FullName‬‬
‫‪6:‬‬ ‫;‪public int Age‬‬
‫} ‪7:‬‬
‫‪8:‬‬
‫‪9: class CB‬‬
‫{ ‪10:‬‬
‫‪11:‬‬ ‫;‪public string FirstName‬‬
‫‪12:‬‬ ‫;‪public string LastName‬‬
‫‪13:‬‬ ‫;‪public double PersonsAge‬‬
‫} ‪14:‬‬
‫‪15:‬‬
‫‪16: class Program‬‬
‫{ ‪17:‬‬
‫‪18:‬‬ ‫)‪static void PrintInfo(CA item‬‬
‫‪19:‬‬ ‫{‬
‫‪20:‬‬ ‫;)‪Console.WriteLine("Name: {0}, Age {1}", item.FullName, item.Age‬‬
‫‪21:‬‬ ‫}‬
‫‪22:‬‬ ‫)(‪static void Main‬‬
‫‪23:‬‬ ‫{‬
‫‪24:‬‬ ‫;} ‪CA a = new CA() { FullName = "John Doe", Age = 35‬‬
‫‪25:‬‬
‫‪26:‬‬ ‫;)‪PrintInfo(a‬‬
‫‪27:‬‬
‫‪28:‬‬ ‫;)(‪Console.ReadLine‬‬
‫‪29:‬‬ ‫}‬
‫} ‪30:‬‬

‫‪173‬‬
‫در کد باال دو کالس ‪ CA‬و ‪ CB‬تعریف شدهاند‪ ،‬در کالس ‪ CA‬دو فیلد به نام ‪ FullName‬و ‪ Age‬و در کالس ‪ CB‬سه فیلد به نامهای ‪ FirstName‬و‬
‫‪ LastName , PersonsAge‬تعریف کردهایم‪ .‬در کالس ‪ Program‬یک متد به نام ()‪ PrintInfo‬داریم که یک پارامتر از نوع کالس ‪ CA‬دارد‪ .‬به‬
‫شکل ساده در این متد مقدار فیلدهای شی ای که به این متد ارسال شده است‪ ،‬چاپ میشود‪ .‬در متد ‪ Main‬یک شیء از کالس ‪ CA‬ساختهایم و فیلدهای آن‬
‫را مقدار دهی کردهایم‪ .‬سپس این شیء را به متد ‪ PrintInfo‬ارسال میکنیم‪ .‬کالسهای ‪ CA‬و ‪ CB‬از نظر مفهومی شبیه یکدیگر هستند‪ .‬مثالً کالس ‪CA‬‬
‫فیلد ‪ FullName‬را برای نمایش نام و نام خانوادگی دارد ولی کالس ‪ CB‬برای نمایش نام و نام خانوادگی دو فیلد جدا از هم به نامهای ‪ FirstName‬و‬
‫‪ LastName‬را دارد‪ .‬و همچنین یک فیلد برای نگهداری مقدار سن داریم که در کالس ‪ CA‬نام آن ‪ Age‬و در کالس ‪ CB‬نام آن ‪ PersonAge‬میباشد‪.‬‬
‫مشکل اینجاست که اگر ما یک شیء از کالس ‪ CA‬را به متد (‪ )PrintInfo‬ارسال کنیم از آنجایی که در داخل بدنه این متد فقط مقدار دو فیلد چاپ میشود‬
‫اگر بخواهیم یک شیء از کالس ‪ CB‬را به آن ارسال کنیم که دارای سه فیلد است با خطا مواجه میشویم (زیرا متد ()‪ PrintInfo‬با ساختار کالس ‪CA‬‬
‫سازگار است و فیلدهای ‪ CB‬را نمیشناسد)‪ .‬برای رفع این مشکل باید ساختار دو کالس ‪ CA‬و ‪ CB‬را شبیه هم کنیم و این کار را با استفاده از ‪Interface‬‬
‫انجام میدهیم‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: interface IInfo‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;)(‪string GetName‬‬
‫‪6:‬‬ ‫;)(‪string GetAge‬‬
‫} ‪7:‬‬
‫‪8:‬‬
‫‪9: class CA : IInfo‬‬
‫{ ‪10:‬‬
‫‪11:‬‬ ‫;‪public string FullName‬‬
‫‪12:‬‬ ‫;‪public int Age‬‬
‫‪13:‬‬ ‫;‪public string GetName() { return FullName‬‬ ‫}‬
‫‪14:‬‬ ‫)(‪public string GetAge‬‬ ‫} ;)(‪{ return Age.ToString‬‬
‫} ‪15:‬‬
‫‪16:‬‬
‫‪17: class CB : IInfo‬‬
‫{ ‪18:‬‬
‫‪19:‬‬ ‫;‪public string FirstName‬‬
‫‪20:‬‬ ‫;‪public string LastName‬‬
‫‪21:‬‬ ‫;‪public double PersonsAge‬‬
‫‪22:‬‬ ‫} ;‪public string GetName() { return FirstName + " " + LastName‬‬
‫‪23:‬‬ ‫)(‪public string GetAge‬‬ ‫;)(‪{ return PersonsAge.ToString‬‬ ‫}‬
‫} ‪24:‬‬
‫‪25:‬‬
‫‪26: class Program‬‬
‫{ ‪27:‬‬
‫‪28:‬‬ ‫)‪static void PrintInfo(IInfo item‬‬
‫‪29:‬‬ ‫{‬
‫‪30:‬‬ ‫;))(‪Console.WriteLine("Name: {0}, Age {1}", item.GetName(), item.GetAge‬‬
‫‪31:‬‬ ‫}‬
‫‪32:‬‬
‫‪33:‬‬ ‫)(‪static void Main‬‬
‫‪34:‬‬ ‫{‬
‫‪35:‬‬ ‫;} ‪CA a = new CA() { FullName = "John Doe", Age = 35‬‬
‫‪36:‬‬ ‫;} ‪CB b = new CB() { FirstName = "Jane", LastName = "Doe", PersonsAge = 33‬‬

‫‪174‬‬
‫‪37:‬‬
‫‪38:‬‬ ‫;)‪PrintInfo(a‬‬
‫‪39:‬‬ ‫;)‪PrintInfo(b‬‬
‫‪40:‬‬
‫‪41:‬‬ ‫;)(‪Console.ReadLine‬‬
‫‪42:‬‬ ‫}‬
‫} ‪43:‬‬

‫کد باال را میتوان به اینصورت توضیح داد که در خط ‪ 3-7‬یک رابط به نام ‪ IInfo‬تعریف و آن را در خطوط ‪ 9‬و ‪ 17‬توسط دو کالس ‪ CA‬و ‪ CB‬پیاده سازی‬
‫کردهایم‪ .‬چون این دو کالس وظیف دارند متدهای این رابط را پیاده سازی کنند پس در خطوط ‪ 13-14‬و ‪ 22-23‬کدهای بدنه دو متد این رابط را آن طور که‬
‫میخواهیم‪ ،‬مینویسیم‪ .‬در خط ‪ 28‬متد ()‪ PrintInfo‬را طوری دستکاری میکنیم که یک پارامتر از نوع رابط دریافت کند‪ .‬حال زمانی که دو شیء از دو کالس‬
‫‪ CA‬و ‪ CB‬در دو خط ‪ 35‬و ‪ 36‬ایجاد میکنیم و آنها را در دو خط ‪ 38‬و ‪ 39‬به متد ()‪ PrintInfo‬ارسال میکنیم‪ ،‬چونکه این دو کالس رابط ‪ IInfo‬را پیاده‬
‫سازی کردهاند به طور صریح به رابط تبدیل میشود‪ .‬یعنی کالسی که یک رابط را پیاده سازی کند به طور صریح میتواند به رابط تبدیل شود‪ .‬حال بسته به اینکه‬
‫شیء کدام کالس به متد ()‪ PrintInfo‬ارسال شده است‪ ،‬متد مربوط به آن کالس فراخوانی شده و مقادیر فیلدها چاپ میشود‪ .‬میتوان چند رابط را در کالس‬
‫اجرا کرد ‪:‬‬

‫‪class Sample : ISample1, ISample2, ISample3‬‬


‫{‬
‫‪//Implement all interfaces‬‬
‫}‬

‫درست است که میتوان از چند رابط در کالس استفاده کرد ولی باید مطمئن شد که کالس میتواند همه اعضای رابطها را تغذیه کند‪ .‬اگر یک کالس از کالس‬
‫پایه ارث ببرد و در عین حال از رابطها هم استفاده کند‪ ،‬در این صورت باید نام کالس پایه قبل از نام رابطها ذکر شود‪ .‬به شکل زیر ‪:‬‬

‫‪class Sample : BaseClass, ISample1, ISample2‬‬


‫{‬
‫}‬

‫همچنین میتوان از عملگر ‪ is‬برای چک کردن اینکه آیا یک شیء خاص از یک رابط استفاده میکند یا نه استفاده کرد ‪:‬‬

‫;)(‪Sample sample = new Sample‬‬

‫)‪if(sample is ISample‬‬
‫{‬
‫;)"!‪Console.WriteLine("sample implements the ISample Interface‬‬
‫}‬

‫نکته دیگر اینکه نمیتوان از یک رابط نمونهای ایجاد کرد چون رابطها دارای سازنده نیستند‪ ،‬مثالً کد زیر اشتباه است ‪:‬‬

‫;)(‪ISample sample = new ISample‬‬

‫کد زیر یک رابط که دارای یک ‪ property‬هست را نشان میدهد ‪:‬‬

‫‪interface ISample‬‬
‫{‬
‫} ;‪int Number { get; set‬‬
‫}‬

‫‪175‬‬
.‫ کالسی که رابط را پیاده سازی میکند آن را اجرا میکند‬.‫ خاصیت نوشته شود‬set ‫ و‬get ‫نباید هیچ کدی در قسمت‬

class Sample : ISample


{
private int number;

public int Number


{
get { return number; }
set { number = value; }
}
}

: ‫ به مثال زیر توجه کنید‬.‫رابطها حتی میتوانند رابطهای دیگر را پیاده سازی یا اجرا کنند‬

1: using System;
2:
3: interface IBase
4: {
5: void BaseMethod();
6: }
7:
8: interface ISample : IBase
9: {
10: void ShowMessage(string message);
11: }
12:
13: public class Sample : ISample
14: {
15: public void ShowMessage(string message)
16: {
17: Console.WriteLine(message);
18: }
19:
20: public void BaseMethod()
21: {
22: Console.WriteLine("Method from base interface!");
23: }
24: }
25:
26: class Program
27: {
28: public static void Main()
29: {
30: Sample sample = new Sample();
31:
32: sample.ShowMessage("Implemented the ISample Interface!");
33: sample.BaseMethod();
34: }
35: }

176
‫مشاهده میکنید که حتی اگر کالس ‪ Sample‬فقط رابط ‪ ISample‬را پیاده سازی کند‪ ،‬الزم است که همه اعضای ‪ IBase‬را هم پیاده سازی کند چون‬
‫‪ ISample‬از آن ارث بری میکند (خط ‪.)8‬‬

‫کالسهای انتزاعی (‪)Abstract Class‬‬

‫کالسهای مجرد (‪ )abstract‬کالسهایی هستند که کالس پایه سایر کالسها هستند‪ .‬این نوع کالسها میتوانند مانند کالسهای عادی دارای سازنده باشند‪.‬‬
‫شما نمی توانید از کالسهای انتزاعی نمونه ایجاد کنید چون که هدف اصلی از به کار بردن کالسهای انتزاعی استفاده از آنها به عنوان کالس پایه برای کالسهای‬
‫مشتق است‪ .‬برای تعریف یک کالس انتزاعی از کلمه کلیدی ‪ abstract‬استفاده میشود‪ .‬به مثال زیر در مورد استفاده از کالسهای انتزاعی توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public abstract class Base‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;‪protected int number‬‬
‫‪6:‬‬ ‫;‪protected string name‬‬
‫‪7:‬‬
‫‪8:‬‬ ‫‪public abstract int Number‬‬
‫‪9:‬‬ ‫{‬
‫‪10:‬‬ ‫;‪get‬‬
‫‪11:‬‬ ‫;‪set‬‬
‫‪12:‬‬ ‫}‬
‫‪13:‬‬
‫‪14:‬‬ ‫‪public string Name‬‬
‫‪15:‬‬ ‫{‬
‫‪16:‬‬ ‫} ;‪get { return name‬‬
‫‪17:‬‬ ‫} ;‪set { name = value‬‬
‫‪18:‬‬ ‫}‬
‫‪19:‬‬
‫‪20:‬‬ ‫;)(‪public abstract void ShowMessage‬‬
‫‪21:‬‬
‫‪22:‬‬ ‫)‪public Base(int number, string name‬‬
‫‪23:‬‬ ‫{‬
‫‪24:‬‬ ‫;‪this.number = number‬‬
‫‪25:‬‬ ‫;‪this.name = name‬‬
‫‪26:‬‬ ‫}‬
‫} ‪27:‬‬
‫‪28:‬‬
‫‪29: public class Derived : Base‬‬
‫{ ‪30:‬‬
‫‪31:‬‬ ‫‪public override void‬‬ ‫)(‪ShowMessage‬‬
‫‪32:‬‬ ‫{‬
‫‪33:‬‬ ‫;)"!‪Console.WriteLine("Hello World‬‬
‫‪34:‬‬ ‫}‬
‫‪35:‬‬
‫‪36:‬‬ ‫‪public override int Number‬‬
‫‪37:‬‬ ‫{‬
‫‪38:‬‬ ‫‪get‬‬
‫‪39:‬‬ ‫{‬
‫‪40:‬‬ ‫;‪return number‬‬
‫‪41:‬‬ ‫}‬

‫‪177‬‬
‫‪42:‬‬ ‫‪set‬‬
‫‪43:‬‬ ‫{‬
‫‪44:‬‬ ‫;‪number = value‬‬
‫‪45:‬‬ ‫}‬
‫‪46:‬‬ ‫}‬
‫‪47:‬‬
‫‪48:‬‬ ‫)‪public Derived(int number, string name‬‬
‫‪49:‬‬ ‫)‪: base(number, name‬‬
‫‪50:‬‬ ‫{‬
‫‪51:‬‬ ‫}‬
‫} ‪52:‬‬

‫در داخل کالس انتزاعی دو فیلد محافظت شده (‪ )protected‬تعریف کردهایم که توسط خواص (‪ )property‬برنامه مورد استفاده قرار میگیرند‪ .‬یکی از‬
‫‪ property‬ها را به صورت انتزاعی (‪ )abstract‬تعریف کردهایم (خط ‪ .)8‬به این نکته توجه کنید که برای تعریف این خاصیت کلمه کلیدی ‪ abstract‬را به‬
‫کار بردهایم‪.‬‬
‫این ‪ property‬باید به وسیله کالسهایی که از این کالس ارث میبرند ‪ override‬شود ولی از آن جاییکه به صورت ‪ abstract‬تعریف شده است قسمتهای‬
‫‪ set‬و ‪ get‬فاقد بدنه هستند‪ .‬میبینید که کالسهای ‪ abstract‬میتوانند شامل ‪ property‬های معمولی مانند ‪ Name ،property‬مثال باال باشند‪.‬‬
‫یک متد ‪ abstract‬تعریف میکنیم‪ .‬همانطور که مشاهده میکنید کالسهای ‪ abstract‬میتوانند شامل ‪ property‬های معمولی مانند خاصیت ‪Name‬‬
‫(خطوط ‪ )16-20‬باشند‪ .‬در کالس مشتق نیز از کلمه کلیدی ‪ abstract‬استفاده شده و کالس باید این متد را ‪ override‬کند (به صورت دیگر پیاده سازی کند‬
‫(خط ‪ .))33‬کالسهای ‪ abstract‬حداقل باید یک عضو ‪ abstract‬داشته باشند‪.‬‬
‫یک کالس دیگر تعریف میکنید که از کالس ‪ Base‬ارث بری کند‪ .‬سپس با استفاده از کلمه کلیدی ‪ override‬یک خاصیت ‪ abstract‬و همچنین‬
‫یک متد را به صورت دیگر پیاده سازی میکنیم (‪ override‬کنیم)(خطوط ‪ 33‬تا ‪ .)48‬همچنین یک سازنده تعریف میکنیم و با استفاده از کلمه کلیدی‬
‫‪ Base‬مقادیر پارامترها را به سازنده پایه ارسال میکنیم‪ .‬نمیتوان از یک کالس ‪ abstract‬نمونه ایجاد کرد ولی از کالسهایی که از این نوع کالسها‬
‫مشتق میشوند‪ ،‬میتوان نمونه ایجاد کرد‪.‬‬

‫کالس تکه تکه (‪)partial class‬‬

‫استفاده از کلمه کلیدی ‪ partial‬به شما اجازه میدهد که یک کالس را در چندین فایل جداگانه تعریف کنید‪ .‬به عنوان مثال میتوانید فیلدها‪ ،‬خاصیتها و‬
‫سازندهها را در یک فایل و متدها را در فایل دیگر قرار دهید‪ .‬برای تعریف این نوع کالسها از کلمه کلیدی ‪ partial‬استفاده میشود‪ .‬در مثال زیر نحوه تعریف‬
‫یک کالس ‪ partial‬در دو فایل جدا نشان داده شده است ‪:‬‬

‫‪public partial class Sample‬‬


‫{‬
‫;‪private int sampleField‬‬

‫‪public int SampleProperty‬‬


‫{‬
‫} ;‪get { return sampleField‬‬
‫} ;‪set { sample = value‬‬
‫}‬
‫}‬
‫‪public partial class Sample‬‬
‫{‬

‫‪178‬‬
‫)(‪public void DoSomething‬‬
‫{‬
‫‪//Do something here‬‬
‫}‬
‫}‬

‫در این مثال مشاهده میکنید که برای تعریف کالسها از کلمه کلیدی ‪ partial‬استفاده شده است‪ .‬همچنین فایلهای جدا در یک کالس به نام ‪ Sample‬تعریف‬
‫شدهاند‪ .‬در قسمت اول (فایل اول) یک فیلد و یک ‪ property‬و در قسمت دوم (فایل دو) یک متد تعریف شده است‪ .‬هنگام ارث بری از کالسها یا پیاده سازی‬
‫رابطها فقط یک بخش از کالسهای ‪ partial‬برای ارث بری نیاز است‪ .‬اگر بخش اول کالس را ‪ IInterface1‬و بخش دوم آن را ‪ IInterface2‬بنامیم در‬
‫نهایت کالس اصلی ترکیبی از این دو بخش خواهد بود‪.‬‬

‫‪public partial class Sample : IInterface1‬‬


‫{‬
‫}‬
‫‪public partial class Sample : IInterface2‬‬
‫{‬
‫}‬

‫میتوان کالس را به صورت زیر نیز نوشت ‪:‬‬

‫‪public class Sample : IInterface1, IInterface2‬‬


‫{‬
‫}‬

‫از کالسهای تکه تکه در فرمهای و‪.‬یندوزی و وب فرمها برای جدا کردن فایلهای کد از فایلهایی که در سرتاسر طراحی این فرمها به کار میروند‬
‫استفاده میشود‪.‬‬

‫کالس مهر و موم شده (‪)Sealed Class‬‬

‫کالس مهر و موم شده (‪ ،)Sealed Class‬کالسی است که دیگر کالسها نمیتوانند از آن ارث بری کنند و چون قابلیت ارث بری ندارد نمیتواند مجرد‬
‫(‪ )abstract‬هم باشد‪ .‬مثال زیر یک کالس مهر و موم شده را نشان میدهد ‪:‬‬

‫‪1: public sealed class Base‬‬


‫{ ‪2:‬‬
‫‪3:‬‬ ‫;‪private int someField‬‬
‫‪4:‬‬
‫‪5:‬‬ ‫‪public int SomeProperty‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫} ;‪get { return someField‬‬
‫‪8:‬‬ ‫} ;‪set { field = value‬‬
‫‪9:‬‬ ‫}‬
‫‪10:‬‬
‫‪11:‬‬ ‫‪public void SomeMethod‬‬
‫‪12:‬‬ ‫{‬
‫‪13:‬‬ ‫‪//Do something here‬‬
‫‪14:‬‬ ‫}‬
‫‪15:‬‬
‫‪16:‬‬ ‫‪//Constructor‬‬

‫‪179‬‬
‫‪17:‬‬ ‫)(‪public Base‬‬
‫‪18:‬‬ ‫{‬
‫‪19:‬‬ ‫‪//Do something here‬‬
‫‪20:‬‬ ‫}‬
‫} ‪21:‬‬
‫‪22:‬‬
‫‪23: public class Derived : Base‬‬
‫{ ‪24:‬‬
‫‪25:‬‬ ‫‪//This class cannot inherit the Base class‬‬
‫} ‪26:‬‬

‫برای تعریف این کالسها از کلمه کلیدی ‪ sealed‬استفاده میشود‪ .‬مشاهده میکنید که کالسهای مهر و موم شده مانند کالسهای عادی‪ ،‬دارای فیلد‪ ،‬خواص‪،‬‬
‫و متد می باشند‪ .‬کالس مشتق در مثال باال با خط قرمز نشان داده شده است چون نمیتواند از کالس پایه ارث بری کند‪ .‬استفاده از این کالسها همانطور که ذکر‬
‫شد زمانی مفید است که بخواهید کالسی ایجاد کنید که از دیگر کالسها ارث بری نکند‪.‬‬

‫چند ریختی (‪)Polymorphism‬‬

‫چند ریختی به کالسهایی که در یک سلسله مراتب وراثتی مشابه هستند‪ ،‬اجازه تغییر شکل و سازگاری مناسب میدهد و همچنین به برنامه نویس این امکان را‬
‫میدهد که به جای ایجاد برنامههای خاص‪ ،‬برنامههای کلی و عمومیتری ایجاد کند‪ ..‬به عنوان مثال‪ ،‬در دنیای واقعی همه حیوانات غذا میخورند‪ ،‬اما روشهای‬
‫غذا خوردن آنها متفاوت است‪ .‬در یک برنامه برای مثال‪ ،‬یک کالس به نام ‪ Animal‬ایجاد میکنید‪ .‬بعد از ایجاد این کالس میتوانید آن را چند ریخت (تبدیل)‬
‫به کالس ‪ Bird‬کنید و متد )(‪ Fly‬را فراخوانی کنید‪ .‬به مثالی درباره چند ریختی توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class Animal‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public virtual void Eat‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;)"!‪Console.WriteLine("The animal ate‬‬
‫‪8:‬‬ ‫}‬
‫} ‪9:‬‬
‫‪10:‬‬
‫‪11: class Dog : Animal‬‬
‫{ ‪12:‬‬
‫‪13:‬‬ ‫)(‪public override void Eat‬‬
‫‪14:‬‬ ‫{‬
‫‪15:‬‬ ‫;)"!‪Console.WriteLine("The dog ate‬‬
‫‪16:‬‬ ‫}‬
‫} ‪17:‬‬
‫‪18:‬‬
‫‪19: class Bird : Animal‬‬
‫{ ‪20:‬‬
‫‪21:‬‬ ‫)(‪public override void Eat‬‬
‫‪22:‬‬ ‫{‬
‫‪23:‬‬ ‫;)"!‪Console.WriteLine("The bird ate‬‬
‫‪24:‬‬ ‫}‬
‫} ‪25:‬‬
‫‪26:‬‬
‫‪27: class Fish : Animal‬‬

‫‪180‬‬
‫{ ‪28:‬‬
‫‪29:‬‬ ‫)(‪public override void Eat‬‬
‫‪30:‬‬ ‫{‬
‫‪31:‬‬ ‫;)"!‪Console.WriteLine("The fish ate‬‬
‫‪32:‬‬ ‫}‬
‫} ‪33:‬‬
‫‪34:‬‬
‫‪35: class Program‬‬
‫{ ‪36:‬‬
‫‪37:‬‬ ‫)(‪public static void Main‬‬
‫‪38:‬‬ ‫{‬
‫‪39:‬‬ ‫;)(‪Dog myDog = new Dog‬‬
‫‪40:‬‬ ‫;)(‪Bird myBird = new Bird‬‬
‫‪41:‬‬ ‫;)(‪Fish myFish = new Fish‬‬
‫‪42:‬‬ ‫;)(‪Animal myAnimal = new Animal‬‬
‫‪43:‬‬
‫‪44:‬‬ ‫;)(‪myAnimal.Eat‬‬
‫‪45:‬‬
‫‪46:‬‬ ‫;‪myAnimal = myDog‬‬
‫‪47:‬‬ ‫;)(‪myAnimal.Eat‬‬
‫‪48:‬‬ ‫;‪myAnimal = myBird‬‬
‫‪49:‬‬ ‫;)(‪myAnimal.Eat‬‬
‫‪50:‬‬ ‫;‪myAnimal = myFish‬‬
‫‪51:‬‬ ‫;)(‪myAnimal.Eat‬‬
‫‪52:‬‬ ‫}‬
‫} ‪53:‬‬

‫!‪The animal ate‬‬


‫!‪The dog ate‬‬
‫!‪The bird ate‬‬
‫!‪The fish ate‬‬
‫همانطور که مشاهده میکنید ‪ 4‬کالس مختلف تعریف کردهایم‪ Animal .‬کالس پایه است و سه کالس دیگر از آن مشتق میشوند‪ .‬هر کالس متد )(‪Eat‬‬
‫مربوط به خود را دارد‪ .‬نمونهای از هر کالس ایجاد کردهایم (‪ .)39-42‬حال متد )(‪ Eat‬را به وسیله نمونه ایجاد شده از کالس ‪ Animal‬به صورت زیر فراخوانی‬
‫میکنیم ‪:‬‬

‫;)(‪Animal myAnimal = new Animal‬‬

‫;)(‪myAnimal.Eat‬‬

‫در مرحله بعد چندریختی روی میدهد‪ .‬همانطور که در مثال باال مشاهده میکنید شی ‪ Dog‬را برابر نمونه ایجاد شده از کالس ‪ Animal‬قرار میدهیم (خط‬
‫‪ )46‬و متد )(‪ Eat‬را بار دیگر فراخوانی میکنیم‪ .‬حال با وجود اینکه ما از نمونه کالس ‪ Animal‬استفاده کردهایم ولی متد )(‪ Eat‬کالس ‪ Dog‬فراخوانی‬
‫میشود‪ .‬این به دلیل تأثیر چند ریختی است‪.‬‬
‫سپس دو شیء دیگر (‪ Bird‬و ‪ )Fish‬را برابر نمونه ایجاد شده از کالس ‪ Animal‬قرار میدهیم و متد )(‪ Eat‬مربوط به هر یک را فراخوانی میکنیم‪( .‬خطوط‬
‫‪ )51-48‬به این نکته توجه کنید که وقتی در مثال باال اشیاء را برابر نمونه کالس ‪ Animal‬قرار میدهیم ازعمل ‪ Cast‬استفاده نکردهایم چون این کار (‪)cast‬‬
‫وقتی که بخواهیم یک شیء از کالس مشتق (مثالً ‪ )Dog‬را در شیی از کالس پایه (‪ )Animal‬ذخیره کنیم الزم نیست‪ .‬همچنین میتوان کالس ‪Animal‬‬
‫را با سازنده هر کالس مشتق دیگر مقدار دهی اولیه کرد ‪:‬‬

‫;)(‪Animal myDog = new Dog‬‬


‫;)(‪Animal myBird = new Bird‬‬

‫‪181‬‬
Animal myFish = new Fish();

myDog.Eat();
myBird.Eat();
myFish.Eat();

: ‫اجازه دهید که برنامه باال را اصالح کنیم تا مفهوم چند ریختی را بهتر متوجه شوید‬

1: using System;
2:
3: class Animal
4: {
5: public virtual void Eat()
6: {
7: Console.WriteLine("The animal ate!");
8: }
9: }
10:
11: class Dog : Animal
12: {
13: public override void Eat()
14: {
15: Console.WriteLine("The dog ate!");
16: }
17:
18: public void Run()
19: {
20: Console.WriteLine("The dog ran!");
21: }
22: }
23:
24: class Bird : Animal
25: {
26: public override void Eat()
27: {
28: Console.WriteLine("The bird ate!");
29: }
30:
31: public void Fly()
32: {
33: Console.WriteLine("The bird flew!");
34: }
35: }
36:
37: class Fish : Animal
38: {
39: public override void Eat()
40: {
41: Console.WriteLine("The fish ate!");
42: }
43:
44: public void Swim()
45: {

182
‫‪46:‬‬ ‫;)"!‪Console.WriteLine("The fish swam‬‬
‫‪47:‬‬ ‫}‬
‫} ‪48:‬‬
‫‪49:‬‬
‫‪50: class Program‬‬
‫{ ‪51:‬‬
‫‪52:‬‬ ‫)(‪public static void Main‬‬
‫‪53:‬‬ ‫{‬
‫‪54:‬‬ ‫;)(‪Animal animal1 = new Dog‬‬
‫‪55:‬‬ ‫;)(‪Animal animal2 = new Bird‬‬
‫‪56:‬‬ ‫;)(‪Animal animal3 = new Fish‬‬
‫‪57:‬‬
‫‪58:‬‬ ‫;‪Dog myDog = (Dog)animal1‬‬
‫‪59:‬‬ ‫;‪Bird myBird = (Bird)animal2‬‬
‫‪60:‬‬ ‫;‪Fish myFish = (Fish)animal3‬‬
‫‪61:‬‬
‫‪62:‬‬ ‫;)(‪myDog.Run‬‬
‫‪63:‬‬ ‫;)(‪myBird.Fly‬‬
‫‪64:‬‬ ‫;)(‪myFish.Swim‬‬
‫‪65:‬‬ ‫}‬
‫} ‪66:‬‬

‫!‪The dog ran‬‬


‫!‪The bird flew‬‬
‫!‪The fish swam‬‬
‫در باال سه شیء از کالس ‪ Animal‬ایجاد و آنها را بوسیله سه سازنده از کالسهای مشتق مقدار دهی اولیه کردهایم (خطوط ‪ .)54-56‬سپس با استفاده از عمل‬
‫‪ cast‬اشیا ایجاد شده از کالس ‪ Animal‬را در نمونههایی از کالسهای مشتق ذخیره میکنیم (خطوط ‪ .)58-60‬وقتی این کار را انجام دادیم‪ ،‬میتوانیم‬
‫متدهای مخصوص به هر یک از کالسهای مشتق را فراخوانی کنیم (خطوط ‪ .) 62-64‬یک را میانبر دیگر به وسیله کد زیر مشخص شده است ولی در این روش‬
‫شما نمیتوانید اشیاء ایجاد شده از کالس ‪ Animal‬را در نمونههایی از کالسهای مشتق ذخیره میکنید‪.‬‬

‫;)(‪((Dog)animal1).Run‬‬
‫;)(‪((Bird)animal2).Fly‬‬
‫;)(‪((Fish)animal3).Swim‬‬

‫از چند ریختی میتوان در رابطها هم استفاده کرد‪ .‬به کد زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: interface IAnimal‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;)(‪void Eat‬‬
‫} ‪6:‬‬
‫‪7:‬‬
‫‪8: class Dog : IAnimal‬‬
‫{ ‪9:‬‬
‫‪10:‬‬ ‫)(‪public void Eat‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫;)"!‪Console.WriteLine("The dog ate‬‬
‫‪13:‬‬ ‫}‬
‫} ‪14:‬‬
‫‪15:‬‬
‫‪16: class Bird : IAnimal‬‬
‫‪183‬‬
17: {
18: public void Eat()
19: {
20: Console.WriteLine("The bird ate!");
21: }
22: }
23:
24: class Fish : IAnimal
25: {
26: public void Eat()
27: {
28: Console.WriteLine("The fish ate!");
29: }
30: }
31:
32: class Program
33: {
34: public static void Main()
35: {
36: IAnimal myDog = new Dog();
37: IAnimal myBird = new Bird();
38: IAnimal myFish = new Fish();
39:
40: myDog.Eat();
41: myBird.Eat();
42: myFish.Eat();
43: }
44: }

The dog ate!


The bird ate!
The fish ate!
.‫تسلط کامل بر چند ریختی و وراثت برای درک بهتر دات نت ضروری است‬

as ‫عملگر‬

‫ این عملگر کاری معادل تبدیل صریح انجام‬.‫ استفاده می شود‬،‫ برای تبدیل یک کالس به کالس دیگر که در سلسله مراتب وراثتی یکسانی هستند‬as ‫از عملگر‬
: ‫ نحوه استفاده از این عملگر به صورت زیر است‬.‫میدهد و فقط دارای تفاوتی جزئی هستند که در ادامه توضیح میدهیم‬

myObject as DestinationType;

‫ کدهای زیر با هم برابر‬.‫ که قرار است شیء به آن تبدیل شود‬،‫ شیی است که قرار است تبدیل شود و عملگر سمت راست نوع مقصد است‬،‫عملگر سمت چپ‬
: ‫هستند‬

Destination someObject = (Destination)myObject;


Destination someObject = myObject as Destination;

184
‫ در کد دوم از‬.‫ (تبدیل صریح) استفاده شده است و اگر تبدیل دو کالس با شکست مواجه شود باعث به وجود آمدن استثناء میشود‬cast ‫در کد اول از عمل‬
‫ شما میتوانید به وسیله این عملگر یک متد از کالس مشتق‬.‫) را بر میگرداند‬null( ‫ استفاده شده است و اگر تبدیل با شکست مواجه شود مقدار تهی‬as ‫عملگر‬
.‫ به مبحث کالسها در درس قبل مراجعه نمایید‬.‫را از طریق کالس پایه فراخوانی کنید‬
(Animal as Dog).Run();

‫سربارگذاری تبدیل ها‬

‫ میتوان از سربارگذاری تبدیلها‬،‫ برای تبدیل یک کالس به یک کالس غیر مرتبط دیگر‬،‫ به عنوان مثال‬.‫تبدیلها را در سی شارپ میتوان سربارگذاری کرد‬
.‫ مثال زیر نشان میدهد که چطور میتوان عملگرهای تبدیل را سربارگذاری کرد‬.‫(صریح و ضمنی) استفاده کرد‬

1: using System;
2:
3: class Animal
4: {
5: public int Height { get; set; }
6:
7: public static implicit operator Plant(Animal animal)
8: {
9: Plant result = new Plant();
10: result.Height = animal.Height;
11: return result;
12: }
13: }
14:
15: class Plant
16: {
17: public int Height { get; set; }
18:
19: public static explicit operator Animal(Plant plant)
20: {
21: Animal result = new Animal();
22: result.Height = plant.Height;
23: return result;
24: }
25: }
26:
27: class Program
28: {
29: public static void Main()
30: {
31: Animal myAnimal = new Animal();
32: myAnimal.Height = 100;
33:
34: //Implicit conversion
35: Plant myPlant = myAnimal;
36:
37: Console.WriteLine("myAnimal.Height = {0}cm", myAnimal.Height);
38: Console.WriteLine("myPlant.Height = {0}cm", myPlant.Height);
39:

185
‫‪40:‬‬ ‫;‪myPlant.Height = 200‬‬
‫‪41:‬‬
‫‪42:‬‬ ‫‪//Explicit conversion‬‬
‫‪43:‬‬ ‫;‪myAnimal = (Animal)myPlant‬‬
‫‪44:‬‬
‫‪45:‬‬ ‫;)‪Console.WriteLine("nmyAnimal.Height = {0}cm", myAnimal.Height‬‬
‫‪46:‬‬ ‫;)‪Console.WriteLine("myPlant.Height = {0}cm", myPlant.Height‬‬
‫‪47:‬‬ ‫}‬
‫} ‪48:‬‬

‫‪myAnimal.Height = 100cm‬‬
‫‪myPlant.Height = 100cm‬‬

‫‪myAnimal.Height = 200cm‬‬
‫‪myPlant.Height = 200cm‬‬
‫در مثال باال مشاهده میکنید که دو کالس ‪ Animal‬و ‪ Planet‬هیچ کدام از دیگری ارث بری نمیکنند و درنتیجه هیچ ارتباطی به هم ندارند‪ .‬برای هر‬
‫کالس یک سربارگذاری تبدیل هم تعریف کردهایم‪ .‬کالس ‪ Animal‬تبدیل ضمنی خود به کالس ‪ Plant‬را سربارگذاری میکند‪ .‬به این نکته توجه کنید که‬
‫برای مشخص کردن اینکه تبدیل ضمنی است یا صریح‪ ،‬به ترتیب از کلمه کلیدی ‪ implicit‬و ‪ explicit‬استفاده کردهایم‪ ،‬و کلمه کلیدی ‪ operator‬نشان‬
‫دهنده این است که متد برای سربارگذاری مورد استفاده قرار میگیرد‪.‬‬
‫نام کالس مقصد را مینویسیم‪ .‬وقتی یک شیء از ‪ Animal‬را به یک شیء ‪ Plant‬اختصاص میدهیم کد داخل متد سربارگذاری شده اجرا میشود‪ .‬متد یک‬
‫پارامتر دارد که ارجاع به نمونه کالسی است که باید تبدیل شود‪ .‬این متد همچنین‪ ،‬نه دارای نوع برگشتی هست و نه نام‪ ،‬در ضمن باید به صورت ‪ public‬و‬
‫‪ static‬تعریف شود‪.‬‬
‫در داخل متد‪ ،‬یک نمونه از کالس ‪ Animal‬را ساخته و مقدار خاصیت ‪ Height‬شیء ‪ Plant‬ارسالی به متد را به خاصیت ‪ Height‬شیء نسبت میدهیم‪.‬‬
‫اساساً‪ ،‬شما باید کدهای الزم برای انتقال مقادیر الزم از شیء مبدأ به شیء مقصد را بنویسید‪ .‬در متد دوم‪ ،‬از کلمه کلیدی ‪ explicit‬به جای ‪ implicit‬استفاده‬
‫کرده ایم‪ .‬این کلمه نشان دهنده تبدیل صریح است‪ .‬دستور زبان نوشتن این تبدیل شبیه به تبدیل قبلی است با این تفاوت که به جای کلمه کلیدی ‪ implicit‬از‬
‫‪ explicit‬استفاده کنید‪ .‬در داخل این متد از کدهای مشابهی برای سربارگذاری استفاده کردهایم‪ .‬به تبدیل ضمنی کالس ‪ Animal‬به ‪ Plant‬توجه فرمایید ‪:‬‬

‫;‪Plant myPlant = myAnimal‬‬

‫نمیتوانیم مکان قرارگیری آنها را بر عکس نماییم ‪:‬‬

‫;‪Animal myAnimal = myPlant‬‬

‫چون که متدی برای تبدیل ضمنی کالس ‪ Plant‬به ‪ Animal‬تعریف نشده است‪ .‬اما چون برای تبدیل صریح متدی را تعریف کردهایم میتوانیم کد را به‬
‫شکل زیر تغییر دهیم ‪:‬‬

‫;‪Animal myAnimal = (Animal)myPlant‬‬

‫برای انجام تبدیل صریح از ‪ casting‬استفاده کردهایم‪.‬‬

‫ایجاد آرایه ای از کالسها‬

‫در این درس به شما نشان میدهیم که‪ ،‬چگونه میتوان آرایهای از کالسها ایجاد کرد‪ .‬ساخت آرایهای از کالسها تقریباً شبیه به ایجاد آرایهای از انواع دادهای‬
‫مانند ‪ int‬است‪ .‬به عنوان مثال میتوان آرایهای از کالس ‪ Person‬ایجاد کرد‪:‬‬

‫‪186‬‬
‫;‪1: using System‬‬
‫‪2:‬‬
‫‪3: public class Person‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫} ;‪public string Name { get; set‬‬
‫‪6:‬‬
‫‪7:‬‬ ‫)‪public Person(string name‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫;‪Name = name‬‬
‫‪10:‬‬ ‫}‬
‫} ‪11:‬‬
‫‪12:‬‬
‫‪13: public class Program‬‬
‫{ ‪14:‬‬
‫‪15:‬‬ ‫)(‪public static void Main‬‬
‫‪16:‬‬ ‫{‬
‫‪17:‬‬ ‫;]‪Person[] people = new Person[3‬‬
‫‪18:‬‬
‫‪19:‬‬ ‫;)"‪people[0] = new Person("Johnny‬‬
‫‪20:‬‬ ‫;)"‪people[1] = new Person("Mike‬‬
‫‪21:‬‬ ‫;)"‪people[2] = new Person("Sonny‬‬
‫‪22:‬‬
‫‪23:‬‬ ‫)‪foreach(Person person in people‬‬
‫‪24:‬‬ ‫{‬
‫‪25:‬‬ ‫;)‪Console.WriteLine(person.Name‬‬
‫‪26:‬‬ ‫}‬
‫‪27:‬‬ ‫}‬
‫} ‪28:‬‬

‫‪Johnny‬‬
‫‪Mike‬‬
‫‪Sonny‬‬
‫ابتدا یک کالس که دارای یک ‪ property‬است تعریف میکنیم‪ .‬سپس یک آرایه از آن (کالس ایجاد شده) تعریف میکنیم و سپس عناصر آن را مانند باال‬
‫مقدار دهی میکنیم‪ .‬سپس مقدار ‪ property‬هر یک از نمونهها را با استفاده از یک حلقه ‪ foreach‬نمایش میدهیم‪ .‬میتوان از تکنیکهای دیگر که قبالً در‬
‫مورد ایجاد آرایه آموختید‪ ،‬هم استفاده کنید‪ .‬مثالً‪ ،‬مثال باال را میتوان به صورت زیر هم نوشت ‪:‬‬

‫][‪Person[] people = new Person‬‬


‫{‬
‫‪new Person("Johnny"),‬‬
‫‪new Person("Mike"),‬‬
‫)"‪new Person("Sonny‬‬
‫;}‬

‫در اینجا‪ ،‬تعداد عناصر آرایه ‪ 3 ،people‬میباشد و کامپایلر هم با شمارش تعداد نمونهها آن را تشخیص میدهد‪ .‬از این تکنیک‪ ،‬برای ساخت آرایههای چند‬
‫بعدی و دندانه دار هم میتوان استفاده کرد‪.‬‬

‫ایندکسر (‪)Indexer‬‬

‫‪187‬‬
‫ مشاهده میکنید میتوان با‬Main ‫ همانطور که در داخل متد‬.‫ که دارای سه فیلد از نوع رشته است تعریف کردهایم‬Person ‫فرض کنید یک کالس به نام‬
.‫استفاده از نام فیلدها به آنها دست یافت‬

using System;

public class Person


{
public string LastName;
public string FirstName;
public string CityOfBirth;
}

class Program
{
static void Main()
{
Person firstPerson = new Person();

firstPerson.LastName = "Doe";
firstPerson.FirstName = "Jane";
firstPerson.CityOfBirth = "Dallas";

Console.WriteLine("{0}", firstPerson.LastName);
Console.WriteLine("{0}", firstPerson.FirstName);
Console.WriteLine("{0}", firstPerson.CityOfBirth);
}
}

Doe
Jane
Dallas
.‫ که در این صورت دسترسی به فیلدها با استفاده از اندیس راحتتر است‬،‫ مانند آرایهای از فیلدها رفتار شود‬،‫ اگر با نمونه ایجاد شده از کالس‬،‫اما در نظر بگیرید‬
Main ‫ تعریف کنید باید کد داخل متد‬Person ‫ اگر بخواهید یک ایندکسر برای کالس‬.‫این دقیقاً کاری است که ایندکسرها به شما اجازه انجام آن را میدهند‬
‫ ولی ایندکسرها از اندیسی که در داخل‬،‫) برای دستیابی به فیلدها استفاده میکند‬.( ‫ به این نکته توجه کنید که نمونه از عالمت دات‬.‫را به صورت زیر تعییر دهید‬
.‫کروشه وجود دارند‬

static void Main()


{
Person firstPerson = new Person();

firstPerson[0] = "Doe";
firstPerson[1] = "Jane";
firstPerson[2] = "Dallas";

Console.WriteLine( "{0}", firstPerson[0] );


Console.WriteLine( "{0}", firstPerson[1] );
Console.WriteLine( "{0}", firstPerson[2] );
}

188
‫تعریف ایندکسر‬

‫دستور تعریف ایندکسر به صورت زیر است‪ .‬به نکاتی در مورد ایندکسرها توجه کنید ‪:‬‬

‫‪ .1‬ایندکسرها اسم ندارند و به جای اسم باید کلمه کلیدی ‪ this‬قرار داده شود‪.‬‬
‫‪ .2‬پارامترها بین کروشه قرار میگیرند‪.‬‬
‫‪ .3‬باید حداقل یک پارامتر داشته باشد‪.‬‬

‫از آنجاییکه همواره یک عضو نمونه است‪ ،‬نباید به صورت ‪ static‬تعریف شود‪.‬‬

‫]‪ReturnType this [Type param1, ...‬‬


‫{‬
‫‪get‬‬
‫{‬
‫‪...‬‬
‫}‬
‫‪set‬‬
‫{‬
‫‪...‬‬
‫}‬
‫}‬

‫تعریف ایندکسر شبیه به تعریف خاصیت است‪ .‬تفاوت و شباهت این دو به صورت زیر است ‪:‬‬
‫بر خالف خاصیت‪ ،‬ایندکسر ‪:‬‬

‫‪ .1‬به جای نام دارای کلمه کلیدی ‪ this‬است‪.‬‬


‫‪ .2‬دارای لیستی از پارامترها است که در داخل یک جفت کروشه قرار دارند‪.‬‬

‫مانند خاصیت‪ ،‬ایندکسر ‪:‬‬

‫‪ .1‬دارای نوع است‪.‬‬


‫‪ .2‬دارای متدهای ‪ get‬و ‪ set‬است‬

‫در مثال زیر یک ‪ Indexer‬برای کالس ‪ Person‬تعریف میکنیم‪ .‬از آنجاییکه این ایندکسر باید فیلدهایی از نوع رشته را مقداردهی کند نوع آن باید ‪string‬‬
‫باشد‪ .‬در داخل این کالس سه فیلد تعریف شده است و برای دسترسی به آنها از سه اندیس ‪ 1 ،0‬و ‪ 2‬استفاده میکنیم‪ ،‬در نتیجه داخل کروشه باید از نوع ‪int‬‬
‫استفاده کنیم‪ .‬در داخل بدنه ‪ set‬و ‪ get‬هم با استفاده از اندیسها میتوانیم مقادیری را به هر یک از فیلدها اختصاص بدهیم یا مقادیر را از آنها بخوانیم ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Person‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;‪public string LastName‬‬
‫‪6:‬‬ ‫;‪public string FirstName‬‬
‫‪7:‬‬ ‫;‪public string CityOfBirth‬‬
‫‪8:‬‬
‫‪189‬‬
9: public string this[int index]
10: {
11: set
12: {
13: switch (index)
14: {
15: case 0: LastName = value;
16: break;
17: case 1: FirstName = value;
18: break;
19: case 2: CityOfBirth = value;
20: break;
20: default: throw new ArgumentOutOfRangeException("index");
21: }
22: }
23:
24: get
25: {
26: switch (index)
27: {
28: case 0: return LastName;
29: case 1: return FirstName;
30: case 2: return CityOfBirth;
20: default: throw new ArgumentOutOfRangeException("index");
31: }
32: }
33: }
34: }
35:
36: class Program
37: {
38: static void Main()
39: {
40: Person firstPerson = new Person();
41: Person secondPerson = new Person();
42:
43: firstPerson[0] = "Doe";
44: firstPerson[1] = "Jane";
45: firstPerson[2] = "Dallas";
46:
47: secondPerson[0] = "Jack";
48: secondPerson[1] = "Rasel";
49: secondPerson[2] = "Chicago";
50:
51: Console.WriteLine("{0}", firstPerson[0]);
52: Console.WriteLine("{0}", firstPerson[1]);
53: Console.WriteLine("{0}", firstPerson[2]);
54:
55: Console.WriteLine("\n");
56:
57: Console.WriteLine("{0}", secondPerson[0]);
58: Console.WriteLine("{0}", secondPerson[1]);
59: Console.WriteLine("{0}", secondPerson[2]);

190
‫‪60:‬‬ ‫}‬
‫} ‪61:‬‬

‫‪Doe‬‬
‫‪Jane‬‬
‫‪Dallas‬‬

‫‪Jack‬‬
‫‪Rasel‬‬
‫‪Chicago‬‬

‫‪String Interpolation‬‬
‫‪ String interpolation‬یا الحاق رشتهها‪ ،‬به شما اجازه میدهد که‪ ،‬عبارات رشتهای با خوانایی بیشتر ایجاد کنید‪ .‬در نسخههای قبلی سی شارپ از متد‬
‫‪ string.format‬برای الحاق رشتهها و در نسخه ‪ 6‬از ویژگی ‪ String interpolation‬برای این کار استفاده میشود‪ .‬دستور استفاده از این ویژگی جدید به‬
‫صورت زیر است ‪:‬‬

‫"‪$"some text {expression} some other text‬‬

‫همانطور که در کد باال مشاهده میکنید‪ ،‬برای الحاق رشتهها قبل از هر رشته یک عالمت ‪ $‬قرار میدهیم‪ .‬در داخل رشته هم یک یا چند عبارت را که در داخل‬
‫آکوالد هستند‪ ،‬مینویسیم‪ .‬این عبارت میتواند یک متغیر و یا حاصل یک یا چند متغیر باشد‪ .‬هر چیز در داخل آکوالد ارزیابی شده و با استفاده از متد‬
‫()‪ ToString‬به رشته تبدیل و در داخل رشته قرار داده میشود‪ .‬اگر بخواهید خود آکوالدها هم پردازش شده و در نتیجه نهایی نمایش داده شوند باید از دو‬
‫عالمت آکوالد استفاده کنید ({{ ‪ .)}} and‬به مثال زیر توجه کنید ‪:‬‬

‫‪1: public class Program‬‬


‫{ ‪2:‬‬
‫‪3:‬‬ ‫)‪public static void Main(string[] args‬‬
‫‪4:‬‬ ‫{‬
‫‪5:‬‬ ‫;"‪string message = "Hello World‬‬
‫‪6:‬‬
‫‪7:‬‬ ‫;"}‪string interpolatedString = $"The message is {message‬‬
‫‪8:‬‬
‫‪9:‬‬ ‫;)‪Console.WriteLine(interpolatedString‬‬
‫‪10:‬‬ ‫}‬
‫} ‪11:‬‬

‫‪The message is Hello World‬‬


‫در خط ‪ 5‬یک رشته تعریف شده است‪ .‬میخواهیم این رشته را به رشته دیگر بچسبانیم‪ .‬برای این کار در خط ‪ 7‬و با استفاده از ویژگی ‪string interpolation‬‬
‫این کار را انجام دادهایم‪ .‬در این خط یک متغیر که نتیجه الحاق دو رشته در آن قرار میگیرد را تعریف کردهایم‪ .‬همانطور که مشاهده میکنید متغیر تعریف شده‬
‫در خط ‪ 5‬را در خط ‪ 7‬داخل عالمت آکوالد قرار دادهایم‪ .‬مقدار این متغیر در داخل عبارت موجود در خط ‪ 7‬قرار میگیرد‪ .‬در مثال زیر نحوه الحاق چندین رشته‬
‫نمایش داده شده است ‪:‬‬

‫‪1: public class Program‬‬


‫{ ‪2:‬‬
‫‪3:‬‬ ‫)‪public static void Main(string[] args‬‬

‫‪191‬‬
4: {
5: string firstName = "John";
6: string lastName = "Smith";
7: int age = 20;
8:
9: Console.WriteLine($"His name is {firstName} {lastName} and his age is {age}.");
10: }
11: }

His name is John Smith and his age is 20.


‫ در مثال زیر تقریب ًا تمام حاالت‬.‫ با استفاده از این ویژگی میتوانیم متغیرهای غیر رشتهای را هم به رشتهها بچسبانیم‬،‫همانطور که در مثال باال مشاهده میکنید‬
: ‫ممکن در الحاق رشته آمده است‬

1: namespace StringInterpolation
2: {
3: public class Program
4: {
5: public static void Main(string[] args)
6: {
7: int num1 = 10;
8: int num2 = 20;
9: string message = "hello world";
10: Person person = new Person { FirstName = "John", LastName = "Smith" };
11:
12: Console.WriteLine($"The sum of num1 and num2 is {num1 + num2}");
13: Console.WriteLine($"num1 less 1 is {num1 - 1}");
14: Console.WriteLine($"num2 divided by num1 is {num2 / num1}");
15:
16: Console.WriteLine($"num1 is equal to num2? {num1 == num2}");
17:
18: Console.WriteLine($"{message} in all caps is {message.ToUpper()}");
19: Console.WriteLine($"num1 added by 100 is {Add100(num1)}");
20:
21: Console.WriteLine($"Full name is {person.FirstName + " " + person.LastName}");
22: }
23:
24: private static int Add100(int number)
25: {
26: return number + 100;
27: }
28: }
29:
30: public class Person
31: {
32: public string FirstName { get; set; }
33: public string LastName { get; set; }
34: }
35: }

The sum of num1 and num2 is 30


num1 less 1 is 9
num2 divided by num1 is 2
num1 is equal to num2? False
192
hello world in all caps is HELLO WORLD
num1 added by 100 is 110
Full name is John Smith
‫ در‬.‫ را بر میگرداند استفاده کردهایم‬false ‫ یا‬true ‫ از دستور شرطی که مقدار‬16 ‫ از عبارات ساده ریاضی به عنوان عبارات الحاقی و در خط‬14 – 12 ‫در خطوط‬
‫ روش قدیمی الحاق رشتهها به کار برده شده است‬21 ‫ در خط‬.‫ از متدهایی استفاده شده که مقدار برگشتی از آنها در عبارات الحاقی قرار میگیرند‬19 ‫ و‬18 ‫خطوط‬
.‫که شما میتوانید از عبارات الحاقی به جای آن استفاده کنید‬

‫قالب بندی عبارات الحاقی‬

‫ برای این کار از کاراکترهای خاص که در درس قالب بندی رشتهها و اعداد آمدهاند میتوان به صورت زیر‬.‫می توان نتیجه یک عبارت الحاقی را قالب بندی کرد‬
: ‫استفاده کرد‬

$"some text {expression:format} some other text"

: ‫به عنوان مثال‬

1: public class Program


2: {
3: public static void Main(string[] args)
4: {
5: double number = 100.1234;
6: DateTime today = DateTime.Now;
7:
8: Console.WriteLine($"Formatted to currency: {number:C}");
9: Console.WriteLine($"2 decimal places {number:F2}");
10: Console.WriteLine($"As percentage: {(number / 100):P}");
11:
12: Console.WriteLine($"Current Month {today:MM}");
13: Console.WriteLine($"Current Day {today:dd}");
14: Console.WriteLine($"Current Hour {today:hh}");
15:
16: Console.WriteLine($"Date today is {today:MM/dd/yyyy hh:mm:ss}");
17: }
18: }

Formatted to currency: $100.12


2 decimal places 100.12
As percentage: 100.12 %
Current Month 08
Current Day 15
Current Hour 04
Date today is 08/15/2015 04:48:28
: ‫لیست کاراکترهای قالب بندی اعداد و تاریخ در لینکهای زیر آمده است‬
https://msdn.microsoft.com/en-us/library/dwhawy9k(v=vs.110).aspx

‫مشخص کردن طول فیلدها‬

193
‫تعیین طول فیلدها برای تراز بندی مقادیر مفید است‪ ،‬مخصوصاً اگر بخواهید که آنها را در ستونهای مختلفی نمایش دهید ‪:‬‬

‫"‪$"some text {expression, fieldWidth} some other text‬‬

‫این یک مثال ساده بود‪ .‬فرض کنید که میخواهیم یک رشته یا عدد را تراز کنیم‪ .‬برای اینکار میتوانی از اعداد مثبت و منفی به صورتی که در مثال زیر آمده‬
‫است‪ ،‬استفاده ک نیم‪ .‬عدد مثبت باعث اضافه شدن فضای خالی به سمت راست و عدد منفی باعث اضافه شدن فضای خالی به سمت چپ عدد یا رشته میشود‪.‬‬
‫البته این تعداد فضای خالی به طول رشته یا عدد بستگی دارد‪ .‬فرض کنید که یک رشته به طول ‪ 5‬کاراکتر داریم و عدد ‪ 10‬را برای اضافه کردن فضای خالی به‬
‫سمت راست آن‪ ،‬به کار میبریم‪ .‬در اینصورت ‪ 10 – 5 = 5‬کاراکتر به سمت راست آن اضافه میشود‪ .‬یعنی تعداد فضاهای خالی اضافه شده از تفاضل طولی فیلد‬
‫و طول رشته به دست میآید ‪:‬‬

‫)‪1: public static void Main(string[] args‬‬


‫{ ‪2:‬‬
‫‪3:‬‬ ‫;‪int number = 100‬‬
‫‪4:‬‬
‫‪5:‬‬ ‫;)"‪Console.WriteLine("Using field width of 10.‬‬
‫‪6:‬‬ ‫;)"‪Console.WriteLine($"Start {number, 10} End‬‬
‫‪7:‬‬
‫‪8:‬‬ ‫;)"‪Console.WriteLine("\nUsing field width of -10.‬‬
‫‪9:‬‬ ‫;)"‪Console.WriteLine($"Start {number,-10} End‬‬
‫} ‪10:‬‬

‫‪Using field width of 10.‬‬


‫‪Start 100‬‬ ‫‪End‬‬

‫‪Using field width of -10.‬‬


‫‪Start‬‬ ‫‪100 End‬‬
‫در مثال باال طول رشته “‪ ”100‬سه کاراکتر است‪ .‬بنابراین ‪ 7‬فضای خالی به سمت راست یا چپ آن اضافه میشود‪ .‬میتوان از ترازبندی و قالب بندی به طور‬
‫همزمان در یک عبارت الحاقی استفاده کرد ‪:‬‬

‫"‪$"some text {expression, fieldWidth:format} some other text‬‬

‫در مثال زیر نحوه استفاده از ترازبندی و قالب بندی به طور همزمان نشان داده شده است ‪:‬‬

‫;‪1: using System‬‬


‫;‪2: using System.Collections.Generic‬‬
‫‪3:‬‬
‫‪4: namespace StringInterpolation‬‬
‫{ ‪5:‬‬
‫‪6:‬‬ ‫‪public class Program‬‬
‫‪7:‬‬ ‫{‬
‫‪8:‬‬ ‫)‪public static void Main(string[] args‬‬
‫‪9:‬‬ ‫{‬
‫‪10:‬‬ ‫>‪List<Product> products = new List<Product‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫‪new Product { ID = 1, Name = "Soap", Price = 5 },‬‬
‫‪13:‬‬ ‫‪new Product { ID = 2, Name = "Toothpaste", Price = 20 },‬‬
‫‪14:‬‬ ‫} ‪new Product { ID = 3, Name = "Portal Gun", Price = 999999999‬‬
‫‪15:‬‬ ‫;}‬
‫‪16:‬‬
‫‪17:‬‬ ‫‪// Print the header‬‬

‫‪194‬‬
‫‪18:‬‬ ‫;)"|}‪Console.WriteLine($"|{ "Code",-5}|{ "Name",-15 }|{ "Price", 20‬‬
‫‪19:‬‬
‫‪20:‬‬ ‫)‪foreach(var p in products‬‬
‫‪21:‬‬ ‫{‬
‫‪22:‬‬ ‫;)"|}‪Console.WriteLine($"|{ p.ID, -5 }|{ p.Name, -15 }|{ p.Price, 20:C‬‬
‫‪23:‬‬ ‫}‬
‫‪24:‬‬ ‫}‬
‫‪25:‬‬ ‫}‬
‫‪26:‬‬
‫‪27:‬‬ ‫‪public class Product‬‬
‫‪28:‬‬ ‫{‬
‫‪29:‬‬ ‫};‪public int ID { get; set‬‬
‫‪30:‬‬ ‫} ;‪public string Name { get; set‬‬
‫‪31:‬‬ ‫} ;‪public decimal Price { get; set‬‬
‫‪32:‬‬ ‫}‬
‫} ‪33:‬‬

‫‪|Code |Name‬‬ ‫|‬ ‫|‪Price‬‬


‫‪|1‬‬ ‫‪|Soap‬‬ ‫|‬ ‫|‪$5.00‬‬
‫‪|2‬‬ ‫‪|Toothpaste‬‬ ‫|‬ ‫|‪$20.00‬‬
‫‪|3‬‬ ‫‪|Portal Gun‬‬ ‫|‬ ‫|‪$999,999,999.00‬‬

‫مدیریت استثناءها و خطایابی‬

‫بهترین برنامه نویسان در هنگام برنامه نویسی با خطاها و باگها در برنامهشان مواجه میشوند‪ .‬درصد زیادی از برنامهها هنگام تست برنامه با خطا مواجه‬
‫می شوند‪ .‬بهتر است برای از بین بردن یا به حداقل رساندن این خطاها‪ ،‬به کاربر در مورد دالیل به وجود آمدن آنها اخطار داده شود‪ .‬خوشبختانه سی شارپ برای‬
‫این مشکل راه حلی ارائه داده است‪ .‬دات نت دارای مجموعه بزرگی از کالسهایی است که برای برطرف کردن خطاهای خاص از آنها استفاده میکند‪ .‬استثناءها در‬
‫دات نت راهی برای نشان دادن دلیل وقوع خطا در هنگام اجرای برنامه است‪.‬‬
‫دات نت دارای مجموعه بزرگی از کالسهای استثناء است که شما میتوانید با استفاده از آنها خطاهایی که در موقعیتهای مختلف روی میدهند را برطرف کنید‪.‬‬
‫حتی میتوانید یک کالس استثناء شخصی ایجاد کنید‪ .‬استثناءها توسط برنامه به وجود میآیند و شما الزم است که آنها را اداره کنید‪ .‬به عنوان مثال در دنیای‬
‫کامپیوتر یک عدد صحیح هرگز نمیتواند بر صفر تقسیم شود‪ .‬اگر بخواهید این کار را انجام دهید (یک عدد صحیح را بر صفر تقسیم کنید)‪ ،‬با خطا مواجه‬
‫میشوید‪ .‬اگر یک برنامه در سی شارپ با چنین خطایی مواجه شود پیغام خطای ”‪ “DivideByZeroException‬نشان داده میشود که بدین معنا است که‬
‫عدد را نمیتوان بر صفر تقسیم کرد‪.‬‬
‫باگ (‪ )Bug‬اصطالحاً خطا یا کدی است که رفتارهای ناخواستهای در برنامه ایجاد میکند‪ .‬خطایابی فرایند برطرف کردن باگها است‪ ،‬بدین معنی که خطاها را از‬
‫برنامه پاک کنیم‪ .‬ویژوال استودیو و ویژوال سی شارپ دارای ابزارهایی برای خطایابی هستند‪ ،‬که خطاها را یافته و به شما اجازه میدهند آنها را برطرف کنید‪ .‬در‬
‫درسهای آینده خواهید آموخت که چگونه از این ابزارهای کارامد جهت برطرف کردن باگها استفاده کنید‪ .‬قبل از اینکه برنامه را به پایان برسانید الزم است که‬
‫برنامهتان را اشکال زدایی کنید‪.‬‬

‫استثناءهای اداره نشده‬

‫استثناءهای اداره نشده‪ ،‬استثناءهایی هستند که به درستی توسط برنامه اداره نشدهاند و باعث میشوند که برنامه به پایان برسد‪ .‬در اینجا میخواهیم به شما نشان‬
‫دهیم که وقتی یک برنامه در زمان اجرا با یک استثناء مواجه میشود و آن را اداره نمیکند چه اتفاقی می افتد‪ .‬در آینده خواهید دید که یک استثناء چگونه به‬
‫‪195‬‬
‫صورت بالقوه باعث نابودی جریان و اجرای برنامه شما میشود‪ .‬از ابتدای آموزش تا کنون برای اجرای برنامهها و نمونه کدها از حالت ‪(Non-Debug‬بدون‬
‫خطایابی) استفاده کردهایم‪ .‬اجرا کردن یک برنامه بدون خطا در حالت ‪ Non-Debug‬یا ‪ Debug‬دارای تفاوتهای جزئی میباشد‪ .‬قصد داریم این تفاوت را‬
‫برای شما توضیح دهیم‪ .‬یک برنامه جدید کنسول ایجاد کرده و نام آن را ‪ ExceptionTest‬میگذاریم‪.‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: namespace ExceptionTest‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫‪public class Program‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫)(‪public static void Main‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫;‪int five = 5‬‬
‫‪10:‬‬ ‫;‪int zero = 0‬‬
‫‪11:‬‬
‫‪12:‬‬ ‫‪//Generate an exception by dividing 5 by 0‬‬
‫‪13:‬‬ ‫;‪int result = five / zero‬‬
‫‪14:‬‬ ‫}‬
‫‪15:‬‬ ‫}‬
‫} ‪16:‬‬

‫همانطور که در مثال باال مشاهده میکنید تقسیم یک عدد صحیح بر صفر غیر مجاز است و باعث ایجاد خطای ‪System.DivideByZeroException‬‬
‫میشود‪.‬‬

‫حالت بدون اداره کردن استثناء (حالت ‪)Non-Debug‬‬

‫برنامه را در حالت ‪ Non-Debug‬به وسیله کلیدهای ترکیبی ‪ Ctrl+F5‬اجرا میکنیم‪ .‬برنامه با موفقیت اجرا شده ولی با پیغام خطای زیر مواجه میشوید ‪:‬‬
‫‪Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.‬‬
‫‪at ExceptionTest.Program.Main() in C:UsersTheUserAppDataLocalTemporary Proje‬‬
‫‪ctsExceptionTestProgram.cs:line 9‬‬
‫و بالفاصله پنجره زیر بعد از بستن برنامه نمایش داده میشود ‪:‬‬

‫نمایش پنجره باال به دلیل وجود یک استثناء اداره نشده است‪ ،‬چون که شما از هیچ کدام از تکنیکهای اداره استثناء استفاده نکردهاید‪ .‬معموالً جزییات باال برای‬
‫کسی که از برنامه شما استفاده میکند الزم نیست‪.‬‬

‫حالت اداره کردن استثناء (‪)Debug Mode‬‬

‫‪196‬‬
‫یکی از راههای بهتر برای دیدن اطالعاتی در مورد استثناءهای اداره نشده استفاده از حالت ‪ Debug‬است‪ .‬برای استفاده از این حالت برنامه را از مسیر ‪Debug‬‬
‫‪ > Start Debugging‬اجرا نمایید‪ .‬همچنین میتوانید از دکمه ‪ F5‬و یا فلش سبزرنگ واقع در ‪ toolbar‬استفاده نمایید‪ .‬به وسیله هر یک از سه حالت باال‬
‫برنامه در حالت ‪ debug‬اجرا میشود‪ .‬در طول اجرای برنامه در این حالت اگر برنامه در قسمتهایی دارای ایراد باشد متوقف شده و خطاهای آن با رنگ زرد‬
‫نمایش داده شود و پنجره دستیار استثناء (‪ )Exception Assistant‬نمایان گردد‪.‬‬

‫پنجره دستیار استثناء پنجره ای مفید است که در مورد استثناء و چگونگی برطرف کردنان اطالعاتی در اختیار شما میگذارد‪ .‬اگر این پنجره مخفی شد به سادگی و‬
‫با کلیک بر روی دستوری که دارای خطا است دوباره ظاهر میشود‪.‬‬

‫دستورات ‪ try‬و ‪catch‬‬

‫میتوان خطاها را با استفاده از دستور ‪ try…catch‬اداره کرد‪ .‬بدین صورت که کدی را که احتمال میدهید ایجاد خطا کند در داخل بلوک ‪ try‬قرار میدهید‪.‬‬
‫بلوک ‪ catch‬هم شامل کدهایی است که وقتی اجرا میشوند که برنامه با خطا مواجه شود‪ .‬تعریف سادهی این دو بلوک به این صورت است که بلوک ‪ try‬سعی‬
‫میک ند که دستورات را اجرا کند و اگر در بین دستورات خطایی وجود داشته باشد برنامه دستورات مربوط به بخش ‪ catch‬را اجرا میکند‪ .‬برنامه زیر نحوه استفاده‬
‫از دستور ‪ try…catch‬را نمایش میدهد ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪6:‬‬ ‫{‬

‫‪197‬‬
7: int result;
8: int x = 5;
9: int y = 0;
10:
11: try
12: {
13: result = x / y; //ERROR
14: }
15: catch
16: {
17: Console.WriteLine("An attempt to divide by 0 was detected.");
18: }
19:
20: }
21: }

An attempt to divide by 0 was detected.


DivideByZeroException ‫ نتیجه محاسبه به وجود آمدن خطای‬.‫ است تقسیم کردهایم‬0 ‫ که مقدار آن‬y ‫ است بر‬5 ‫ را که‬x ‫ مقدار‬،try ‫در داخل بلوک‬
: ‫ بنابراین‬.‫ اجرا میشوند‬catch ‫ از آنجاییکه در برنامه باال خطایی به وجود آمده است کدهای داخل بلوک‬.‫(عدد تقسیم بر صفر) است‬

try
{
result = x / y; //Error: Jump to catch block
Console.WriteLine("This line will not be executed.");
}
catch
{
Console.WriteLine("An attempt to divide by 0 was detected.");
}

‫ مثالً برای خطای تقسیم عدد بر صفر از‬،‫ استفاده کنید‬catch ‫میتوانید از یک نوع استثناء مخصوص به یک خطا در داخل بلوک‬
: ‫ به شکل زیر استفاده کنید‬DivideByZeroException

try
{
result = x / y; //ERROR
}
catch (DivideByZeroException)
{
Console.WriteLine("An attempt to divide by 0 was detected.");
}

:‫همچنین میتوانید اطالعات مربوط به یک استثنا را در داخل یک متغیر قرار داده و سپس آن را نمایش دهید‬

try
{
result = x / y; //ERROR
}
catch (DivideByZeroException error)
{
Console.WriteLine(error.Message);

198
‫}‬

‫‪Attempted to divide by zero.‬‬


‫در کد باال یک نمونه از کالس ‪ DivideByZeroException‬را ایجاد کردهایم (‪ .)error‬این کالس دارای یک خاصیت به نام ‪ Message‬است که از‬
‫آن برای نمایش اطالعاتی در مورد استثناء استفاده میکنیم‪ .‬همه کالسهای استثناء توضیحاتی در مورد خطاها میدهند‪ .‬در درسهای آینده در مورد خصوصیات‬
‫استثناءها بیشتر توضیح میدهیم‪ .‬اگر فکر میکنید که در بلوک ‪ try‬ممکن است با چندین خطا مواجه شوید میتوانید از چندین بلوک ‪ catch‬استفاده نمایید ولی‬
‫به یاد داشته باشید که برای هر کدام از آن خطاها از کالس استثناء مربوط به هر یک استفاده کنید‪.‬‬

‫;‪int result‬‬
‫;‪int x = 5‬‬
‫;‪int y‬‬

‫‪try‬‬
‫{‬
‫;))(‪y = Int32.Parse(Console.ReadLine‬‬
‫;‪result = x / y‬‬
‫}‬
‫)‪catch (DivideByZeroException error‬‬
‫{‬
‫;)‪Console.WriteLine(error.Message‬‬
‫}‬
‫)‪catch (FormatException error‬‬
‫{‬
‫;)‪Console.WriteLine(error.Message‬‬
‫}‬

‫از انجاییکه مقدار ‪ y‬به وسیله ورودی که از کاربر گرفته میشود‪ ،‬تعیین می شود‪ ،‬مقدار آن باید با توجه به مثال باال غیر صفر باشد (عدد تقسیم بر صفر تعریف‬
‫نشده است)‪ .‬اما یک مشکل وجود دارد‪ .‬چون ممکن است که کاربر یک مقدار غیر عددی وارد کند (مثالً یک حرف) که در این صورت برنامه نمیتواند حرف را به‬
‫عدد تبدیل کند و خطای نوع (‪ )FormatException‬اتفاق می افتد‪ .‬وقتی استثناء اتفاق افتاد بلوک ‪ catch‬مربوط به این خطا اجرا میشود و محاسبه خارج‬
‫قسمت تقسیم ‪ x‬بر ‪ y‬نادیده گرفته میشود‪ .‬حال فرض کنید شما میخواهید تمام خطاهای احتمالی که ممکن است در داخل بلوک ‪ try‬اتفاق می افتند را‬
‫فهمیده و اداره کنید این کار چگونه امکانپذیر است؟ به راحتی و با استفاده از کالس عمومی ‪ Exception‬میتوانید این کار را انجام داد‪ .‬هر کالس استثناء در‬
‫دات نت از این کالس ارث بری میکند بنابراین شما میتوانید هر نوع استثناءیی را در شئی از کالس ‪ Exception‬ذخیره نمایید‪.‬‬

‫‪try‬‬
‫{‬
‫‪//Put your codes to test here‬‬
‫}‬
‫)‪catch (Exception error‬‬
‫{‬
‫;)‪Console.WriteLine(error.Message‬‬
‫}‬

‫با استفاده از این روش دیگر الزم نیست نگران اتفاق خطاهای احتمالی باشید چون بلوک ‪ catch‬برای هر گونه خطایی که در داخل بلوک ‪ try‬تشخیص داده‬
‫شود پیغام مناسبی نشان میدهد‪ .‬به این نکته توجه کنید که اگر بخواهید از کالس پایه ‪ Exception‬همراه با سایر کالسهای استثناء دیگر که از آن مشتق‬
‫میشوند در برنامه استفاده کنید باید کالس پایه ‪ Exception‬در آخرین بلوک ‪ catch‬قرار گیرد‪.‬‬

‫‪try‬‬
‫{‬
‫‪//Put your codes to test here‬‬

‫‪199‬‬
‫}‬
‫)‪catch (DivideByZeroException‬‬
‫{‬
‫;)"‪Console.WriteLine("Division by zero is not allowed.‬‬
‫}‬
‫)‪catch (FormatException‬‬
‫{‬
‫;)"‪Console.WriteLine("Error on converting the data to proper type.‬‬
‫}‬
‫)‪catch (Exception‬‬
‫{‬
‫;)"‪Console.WriteLine("An error occured.‬‬
‫}‬

‫اگر کالس پایه ‪ Exception‬را در اولین بلوک ‪ catch‬قرار دهیم و خطایی در برنامه رخ دهد چون تمام کالسهای استثناء از این کالس مشتق میشوند در‬
‫نتیجه اولین بلوک ‪ catch‬اجرا شده و سایر بلوکها حتی با وجود اینکه خطای مورد نظر به آنها مربوط باشد اجرا نمیشوند‪ .‬شما میتوانید از عمگر ‪ is‬نیز به‬
‫صورت زیر استفاده نمایید‪.‬‬

‫‪try‬‬
‫{‬

‫}‬
‫)‪catch(Exception error‬‬
‫{‬
‫)‪if (error is DivideByZeroException‬‬
‫{‬
‫;)"!‪Console.WriteLine("Cannot divide by zero‬‬
‫}‬
‫)‪if (error is FormatException‬‬
‫{‬
‫;)"!‪Console.WriteLine("Format cannot be accepted‬‬
‫}‬
‫}‬

‫بلوک ‪ catch‬از کالس ‪ Exception‬برای به دام انداختن همه استثناءهایی که به وسیله برنامه به وجود میآید استفاده میکند‪ .‬در داخل بلوک ‪catch‬‬
‫میتوانید با استفاده از یک دستور ‪ if‬و کلمه کلیدی ‪ is‬نوع استثناء به وجود آمده را بیابید‪.‬‬

‫استفاده از بلوک ‪finally‬‬

‫گاهی اوقات میخواهید برخی کدها همیشه اجرا شوند خواه استثناء رخ دهد‪ ،‬خواه رخ ندهد‪ ،‬در این صورت از بلوک ‪ finally‬استفاده میشود‪ .‬قبالً یاد گرفتیم که‬
‫اگر در بلوک ‪ try‬یک استثناء رخ دهد همه کدهای موجود در این بلوک نادیده گرفته شده و برنامه به قسمت ‪ catch‬میرود‪ .‬کدهای نادیده گرفته شده ممکن‬
‫است در برنامه نقش حیاتی داشته باشند‪.‬‬
‫هدف بلوک ‪ finally‬هم حفظ نقش این کدها به صورت غیر مستقیم است‪ .‬کدهایی را که فکر میکنید کدهای پایهای هستند و برای اجرای برنامه الزم هستند‬
‫را در داخل بلوک ‪ finally‬قرار دهید‪ .‬برنامه زیر نحوه استفاده از این بلوک را نشان میدهد ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪200‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪int result‬‬
‫‪8:‬‬ ‫;‪int x = 5‬‬
‫‪9:‬‬ ‫;‪int y = 0‬‬
‫‪10:‬‬
‫‪11:‬‬ ‫‪try‬‬
‫‪12:‬‬ ‫{‬
‫‪13:‬‬ ‫;‪result = x / y‬‬
‫‪14:‬‬ ‫}‬
‫‪15:‬‬ ‫)‪catch(DivideByZeroException error‬‬
‫‪16:‬‬ ‫{‬
‫‪17:‬‬ ‫;)‪Console.WriteLine(error.Message‬‬
‫‪18:‬‬ ‫}‬
‫‪19:‬‬ ‫‪finally‬‬
‫‪20:‬‬ ‫{‬
‫‪21:‬‬ ‫;)"‪Console.WriteLine("finally blocked was reached.‬‬
‫‪22:‬‬ ‫}‬
‫‪23:‬‬ ‫}‬
‫} ‪24:‬‬

‫‪Attempted to divide by zero.‬‬


‫‪finally blocked was reached.‬‬
‫بلوک ‪ finally‬بعد از بلوک ‪ catch‬نوشته میشود‪ .‬اگر از چندین بلوک ‪ catch‬در برنامه استفاده میکنید بلوک ‪ finally‬باید بعد از همه آنها قرار گیرد‪.‬‬
‫میتوان از بلوک ‪ try‬و ‪ finally‬در صورتی که بلوک ‪ catch‬نداشته باشیم به صورت زیر استفاده کرد‪.‬‬

‫‪try‬‬
‫{‬
‫‪//some code‬‬
‫}‬
‫‪finally‬‬
‫{‬
‫‪//some code‬‬
‫}‬

‫از این بلوک معموالً برای بستن یک اتصال پایگاه داده یا بستن یک فایل استفاده میشود‪.‬‬

‫استفاده از بلوک ‪finally‬‬

‫گاهی اوقات میخو اهید برخی کدها همیشه اجرا شوند خواه استثناء رخ دهد‪ ،‬خواه رخ ندهد‪ ،‬در این صورت از بلوک ‪ finally‬استفاده میشود‪ .‬قبالً یاد گرفتیم که‬
‫اگر در بلوک ‪ try‬یک استثناء رخ دهد همه کدهای موجود در این بلوک نادیده گرفته شده و برنامه به قسمت ‪ catch‬میرود‪ .‬کدهای نادیده گرفته شده ممکن‬
‫است در برنامه نقش حیاتی داشته باشند‪.‬‬
‫هدف بلوک ‪ finally‬هم حفظ نقش این کدها به صورت غیر مستقیم است‪ .‬کدهایی را که فکر میکنید کدهای پایهای هستند و برای اجرای برنامه الزم هستند‬
‫را در داخل بلوک ‪ finally‬قرار دهید‪ .‬برنامه زیر نحوه استفاده از این بلوک را نشان میدهد ‪:‬‬

‫;‪1: using System‬‬

‫‪201‬‬
‫‪2:‬‬
‫‪3: public class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪int result‬‬
‫‪8:‬‬ ‫;‪int x = 5‬‬
‫‪9:‬‬ ‫;‪int y = 0‬‬
‫‪10:‬‬
‫‪11:‬‬ ‫‪try‬‬
‫‪12:‬‬ ‫{‬
‫‪13:‬‬ ‫;‪result = x / y‬‬
‫‪14:‬‬ ‫}‬
‫‪15:‬‬ ‫)‪catch(DivideByZeroException error‬‬
‫‪16:‬‬ ‫{‬
‫‪17:‬‬ ‫;)‪Console.WriteLine(error.Message‬‬
‫‪18:‬‬ ‫}‬
‫‪19:‬‬ ‫‪finally‬‬
‫‪20:‬‬ ‫{‬
‫‪21:‬‬ ‫;)"‪Console.WriteLine("finally blocked was reached.‬‬
‫‪22:‬‬ ‫}‬
‫‪23:‬‬ ‫}‬
‫} ‪24:‬‬

‫‪Attempted to divide by zero.‬‬


‫‪finally blocked was reached.‬‬
‫بلوک ‪ finally‬بعد از بلوک ‪ catch‬نوشته میشود‪ .‬اگر از چندین بلوک ‪ catch‬در برنامه استفاده میکنید بلوک ‪ finally‬باید بعد از همه آنها قرار گیرد‪.‬‬
‫میتوان از بلوک ‪ try‬و ‪ finally‬در صورتی که بلوک ‪ catch‬نداشته باشیم به صورت زیر استفاده کرد‪.‬‬

‫‪try‬‬
‫{‬
‫‪//some code‬‬
‫}‬
‫‪finally‬‬
‫{‬
‫‪//some code‬‬
‫}‬

‫از این بلوک معموالً برای بستن یک اتصال پایگاه داده یا بستن یک فایل استفاده میشود‪.‬‬

‫ایجاد استثناء‬

‫شما می توانید در هر جای برنامه یک خطای ساختگی ایجاد کنید‪ .‬همچنین اگر پیغام پیشفرض استثناءها را دوست ندارید میتوانید به دلخواه خودتان یک پیغام‬
‫برای نمایش ایجاد کنید‪ .‬به مثال زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪202‬‬
6: {
7: int firstNumber, secondNumber, result;
8:
9: Console.Write("Enter the first number: ");
10: firstNumber = Int32.Parse(Console.ReadLine());
11:
12: Console.Write("Enter the second number: ");
13: secondNumber = Int32.Parse(Console.ReadLine());
14:
15: try
16: {
17: if (secondNumber == 0)
18: {
19: throw new DivideByZeroException();
20: }
21: else
22: {
23: result = firstNumber / secondNumber;
24: }
25: }
26: catch (DivideByZeroException error)
27: {
28: Console.WriteLine(error.Message);
29: }
30: }
31: }

Enter the first number: 10


Enter the second number: 0
Attempted to divide by zero.
‫ میتوان مستقیماً یک نمونه از کالس‬.‫ استفاده کردهایم‬throw ‫ از کلمه کلیدی‬exception ‫ و درست قبل از یک نمونه ایجاد شده از کالس‬19 ‫در خط‬
: ‫ به مثال زیر توجه کنید‬.‫ ایجاد و یک خطا را به دام انداخت‬exception

DivideByZeroException error = new DivideByZeroException();

throw error;

‫ که یک رشته را دریافت و آن را به عنوان پیغام‬Exception ‫همچنین می توان یک پیغام خطای سفارشی را به وسیله یکی دیگر از سربارگذاری های کالس‬
.‫ نمایش داد‬،‫خطا نمایش میدهد‬

throw new DivideByZeroException("Cannot divide by zero!");

‫ ایجاد استثناء بیشتر در مواقعی به کار میرود که یک کد در حالت‬.‫ ذخیره میشود‬Message ‫در این حالت پیغام خطای پیشفرض تغییر کرده و در خاصیت‬
.‫عادی خطا ندارد ولی شما میخواهید در هر صورت به عنوان یک خطا در نظر گرفته شود‬

Exception ‫خواص‬

203
‫کالس پایه ‪ System.Exception‬کالسی است که سایر کالسهای استثناء از آن ارث بری میکنند‪ .‬بنابراین خواص این کالس در دسترس سایر کالسهای‬
‫استثناء میباشد‪ .‬در جدول زیر برخی از خواص برجسته کالس ‪ Exception‬که در همه کالسهای استثناء وجود دارند آمده است ‪:‬‬
‫توضیحات‬ ‫خواص‬

‫‪ InnerException‬استثنایی که موجب تولید مشکل شده است‬

‫متنی که استثناء را شرح میدهد‬ ‫‪Message‬‬

‫برای تشخیص خطایی که باعث ایجاد مشکل شده است‬ ‫‪StackTrace‬‬

‫خاصیت ‪Message‬‬

‫این خاصیت به شما اجازه میدهد که در مورد استثناء به وجود آمده توضیحاتی ارائه دهید‪ .‬به عنوان مثال به کد زیر توجه کنید ‪:‬‬

‫;‪int x = 1‬‬
‫;‪int y = 0‬‬
‫;‪int z‬‬

‫‪try‬‬
‫{‬
‫;‪z = x / y‬‬
‫}‬
‫)‪catch (Exception ex‬‬
‫{‬
‫;)‪Console.WriteLine(ex.Message‬‬
‫}‬

‫‪Attempted to divide by zero.‬‬


‫در مثال باال عمداً یک عدد را بر صفر تقسیم میکنیم تا بلوک ‪ catch‬اجرا شود‪ .‬به این نکته توجه کنید که چون یک نمونه از کالس ‪ Exception‬ایجاد‬
‫کردهایم بنابراین میتوانیم از خاصیت ‪ Message‬استفاده کنیم‪ .‬سپس محتویات خاصیت ‪ Message‬را به وسیله متد ()‪ Console.WriteLine‬چاپ‬
‫میکنیم‪ .‬حال اگر برنامه را اجرا کنیم پیغام خطا نمایش داده میشود‪ .‬همه کالسهای استثناء از قبل تعریف شده در دات نت پیغام خطاهای مرتبط با خودشان را در‬
‫خاصیت ‪ property‬دارند‪ .‬اگر یک استثناء ایجاد کنید میتوانید از سربارگذاری سازنده کالس ‪ Exception‬که یک رشته که همان پیغام خطاست را دریافت‬
‫میکند‪ ،‬استفاده کنید‬

‫‪try‬‬
‫{‬
‫)‪if (y == 0‬‬
‫{‬
‫;)"‪throw new DivideByZeroException("You cannot divide by zero. Sorry my friend.‬‬
‫}‬
‫‪else‬‬
‫{‬
‫;‪z = x / y‬‬
‫}‬
‫}‬
‫)‪catch (Exception e‬‬

‫‪204‬‬
{
Console.WriteLine(e.Message);
}

You cannot divide by zero. Sorry my friend.

InnerException ‫خاصیت‬

‫ به عنوان مثال فرض کنید که یک برنامه نویس میخواهد تشخیص دهد‬.‫از این خاصیت برای تشخیص خطایی که باعث ایجاد مشکل شده است استفاده میشود‬
‫ اگر عدد وارد‬.‫که آیا شماره حسابی که توسط کاربر وارد شده است صحیح می باشد یا نه؟ اولین کاری که باید انجام شود تبدیل نوع رشته به عدد صحیح است‬
‫ برای‬chatch ‫ در قسمت‬.‫ رخ میدهد‬FormatException ‫شده توسط کاربر که از نوع رشته است را نتوانیم به درستی به نوع عدد تبدیل کنیم خطای‬
: ‫ به کد زیر توجه کنید‬.‫ می توان مانور بیشتری داد و استثناء رو مدیریت کرد و پیغام مناسب را به کاربر نشان داد‬،FormatException

1: using System;
2:
3: namespace InnerExceptionDemo
4: {
5: class Program
6: {
7: static int ProcessAccountNumber(string accountNumber)
8: {
9: try
10: {
11: return Convert.ToInt32(accountNumber);
12: }
13: catch (FormatException formatException)
14: {
15: throw new Exception("Invalid Account Number.", formatException);
16: }
17: }
18: static void Main(string[] args)
19: {
20: Console.Write("Enter an account number: ");
21: string input = Console.ReadLine();
22:
23: try
24: {
25: int accountNumber = ProcessAccountNumber(input);
26: }
27: catch (Exception ex)
28: {
29: Console.WriteLine("Current exception's message: {0}", ex.Message);
30: Console.WriteLine("Inner exception's message: {0}",
31: ex.InnerException.Message);
32: }
33: }
34: }
35: }

Enter an account number: abcde

205
‫‪Current exception's message: Invalid Account Number.‬‬
‫‪Inner exception's message: Input string was not in a correct format.‬‬
‫در خطوط ‪ 7-17‬یک متد به نام ‪ ProcessAccountNumber‬تعریف کردهایم‪ .‬این متد یک آرگومان از نوع رشته قبول میکند که همان رشتهای است که‬
‫توسط کاربر وارد میشود‪ .‬همانطور که در خط ‪ 25‬مشاهده میکنید متد (‪ ) ProcessAccountNumber‬فراخوانی شده و رشته وارد شده توسط کاربر به‬
‫عنوان آرگومان به آن ارسال میشود‪ .‬این خط کد (خط ‪ )25‬در داخل یک بلوک ‪ try‬قرار داده میشود چون ممکن است باعث ایجاد خطا شود‪ .‬بعد از اینکه متد‬
‫فراخوانی شد برنامه به محل تعریف متد منتقل میشود (خط ‪ .)7‬در داخل متد دستور ‪ try…catch‬دیگری وجود دارد‪ .‬در داخل بلوک ‪ try‬سعی میکنیم که‬
‫رشته را به عدد تبدیل کرده و مقدار آن را برگشت دهیم‪ .‬اگر رشته نتواند به عدد تبدیل شود خطای ‪ FormatException‬رخ داده م در نتیجه بلوک ‪catch‬‬
‫میشود‪.‬‬ ‫اجرا‬
‫در داخل بلوک ‪ catch‬یک نمونه از کالس ‪ Exception‬ایجاد کرده و پیغام دلخواه به عنوان اولین پارامتر ورودی و ‪ FormatException‬را به عنوان‬
‫پارامتر دوم که نشان دهنده یک ‪ InnerException‬است را برای آن مشخص میکنیم‪ .‬بعد از اجرای این قسمت بالک ‪ catch‬تابع اصلی یعنی خط ‪ 27‬اجرا‬
‫خواهد شد‪ .‬در این بالک اول ‪ Exception‬جدید و خاصیت ‪ Message‬آن نمایش داده میشود و بعد از آن خاصیت ‪ Message‬استثناء ای که باعث اجرای‬
‫این بالک شد است به عنوان ‪ InnerException‬نمایش داده میشود‪.‬‬

‫خاصیت ‪StackTrace‬‬

‫خاصیت ‪ StackTrace‬در کالس ‪ System.Exception‬به شما اجازه میدهد تا بفهمید در کدام متد از متدهای پشته خطا رخ داده است‪ .‬این خاصیت‬
‫برای زمانی است که شما متد ‪ 1‬را داخل متد ‪ 2‬صدا زدهاید و متد ‪ 1‬دارای خطا است‪ .‬با استفاده از این خاصیت میتوانید بفمید که در متد ‪ 1‬و به دنبال آن در متد‬
‫‪ 2‬هم خطا رخ داده است‪ .‬به کد زیر دقت کنید‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: namespace StackTraceDemo‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫‪class Program‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫)(‪static void Method1‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫;)(‪Method2‬‬
‫‪10:‬‬ ‫}‬
‫‪11:‬‬
‫‪12:‬‬ ‫)(‪static void Method2‬‬
‫‪13:‬‬ ‫{‬
‫‪14:‬‬ ‫;)(‪Method3‬‬
‫‪15:‬‬ ‫}‬
‫‪16:‬‬
‫‪17:‬‬ ‫)(‪static void Method3‬‬
‫‪18:‬‬ ‫{‬
‫‪19:‬‬ ‫;)")(‪throw new Exception("Exception at Method3‬‬
‫‪20:‬‬ ‫}‬
‫‪21:‬‬
‫‪22:‬‬ ‫)‪static void Main(string[] args‬‬
‫‪23:‬‬ ‫{‬
‫‪24:‬‬ ‫‪try‬‬
‫‪25:‬‬ ‫{‬
‫‪26:‬‬ ‫;)(‪Method1‬‬
‫‪27:‬‬ ‫}‬
‫‪28:‬‬ ‫)‪catch (Exception ex‬‬

‫‪206‬‬
29: {
30: Console.WriteLine(ex.StackTrace);
31: Console.ReadKey();
32: }
33: }
34: }
35: }

at StackTraceDemo.Program.Method3() in C:StackTraceDemoProgram.cs:line 19
at StackTraceDemo.Program.Method2() in C:StackTraceDemoProgram.cs:line 14
at StackTraceDemo.Program.Method1() in C:StackTraceDemoProgram.cs:line 9
at StackTraceDemo.Program.Main(String[] args) in C:StackTraceDemoProgram.cs:line 26
.‫ به عنوان منبع خطا در اولین خط نشان داده شده است‬3 ‫ متد‬.‫ فایل و متد و خطِ دارای خطا را نشان میدهد‬3 ‫هر خط‬

‫تعریف یک استثناء توسط کاربر‬

‫ ارث‬Exception ‫ استثناء سفارشی استثنایی است که توسط کاربر تعریف میشود و باید از کالس پایه‬.‫در سی شارپ میتوان یک استثناء سفارشی ایجاد کرد‬
‫ یک برنامه کنسول ایجاد کنید و نام آن را‬.‫ ارث میبرد ایجاد میکنیم‬Exception ‫ برای این کار یک کالس جداگانه که از کالس پایه‬.‫بری کند‬
.‫بگذارید‬ UserDefinedExceptions
‫) کلیک کنید و از پنجره باز شده گزینه‬toolbar( ‫) در نوار ابزار‬Project>Add New Item ‫ (مسیر‬Add New Item ‫بعد از ایجاد پروژه بر روی دکمه‬
.‫ را انتخاب کنید‬Class
.‫ بگذارید‬NegativeNumberException ‫نام کالس را‬

1: using System;
2:
3: namespace UserDefinedExceptions
4: {
5: class NegativeNumberException : Exception
6: {
7: public NegativeNumberException()
8: : base("The operation will result to a negative number.")
9: {
10: }
11:
12: public NegativeNumberException(string message)
13: : base(message)
14: {
15: }
16:
17: public NegativeNumberException(string message, Exception inner)
18: : base(message, inner)
19: {
20: }
21: }
22: }

207
‫در خط ‪ 5‬مشاهده میکنید کالس ایجاد شده توسط ما از کالس ‪ Exception‬ارث بری کرده است‪ .‬به عنوان یک قرارداد باید به آخر نام کالسهای استثنایی‬
‫که توسط کاربر تعریف میشوند کلمه ‪ Exception‬اضافه شده و ‪ 3‬سازنده برای آنها تعریف شود‪.‬‬
‫میباشد‪.‬‬ ‫پارامتر‬ ‫بدون‬ ‫سازنده‬ ‫اولین‬
‫میکند‪.‬‬ ‫قبول‬ ‫خطا‬ ‫پیغام‬ ‫نمایش‬ ‫برای‬ ‫رشته‬ ‫نوع‬ ‫از‬ ‫آرگومان‬ ‫یک‬ ‫سازنده‬ ‫دومین‬
‫سومین سازنده که دو آرگومان قبول میکند‪ ،‬یکی پیغام خطا را نمایش داده و یکی بخش ‪ inner‬است آن برای نشان دادن علت وقوع استثناء میباشد‪ .‬حال‬
‫میخواهیم یک کالس استثناء خیلی سفارشی ایجاد کنیم‪ .‬در فایل ‪ Program.cs‬کد زیر را وارد کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: class Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫)(‪public static void Main‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫;‪int firstNumber, secondNumber, difference‬‬
‫‪8:‬‬
‫‪9:‬‬ ‫;)" ‪Console.Write("Enter the first number:‬‬
‫‪10:‬‬ ‫;))(‪firstNumber = Int32.Parse(Console.ReadLine‬‬
‫‪11:‬‬
‫‪12:‬‬ ‫;)" ‪Console.Write("Enter the second number:‬‬
‫‪13:‬‬ ‫;))(‪secondNumber = Int32.Parse(Console.ReadLine‬‬
‫‪14:‬‬
‫‪15:‬‬ ‫;‪difference = firstNumber - secondNumber‬‬
‫‪16:‬‬
‫‪17:‬‬ ‫‪try‬‬
‫‪18:‬‬ ‫{‬
‫‪19:‬‬ ‫)‪if (difference < 0‬‬
‫‪20:‬‬ ‫{‬
‫‪21:‬‬ ‫;)(‪throw new NegativeNumberException‬‬
‫‪22:‬‬ ‫}‬
‫‪23:‬‬ ‫}‬
‫‪24:‬‬ ‫)‪catch (NegativeNumberException error‬‬
‫‪25:‬‬ ‫{‬
‫‪26:‬‬ ‫;)‪Console.WriteLine(error.Message‬‬
‫‪27:‬‬ ‫}‬
‫‪28:‬‬ ‫}‬
‫} ‪29:‬‬

‫‪Enter the first number: 10‬‬


‫‪Enter the second number: 11‬‬
‫‪The operation will result to a negative number.‬‬
‫از آنجاییکه تولید یک عدد منفی در هیچ برنامهای یک استثناء محسوب نمیشود‪ ،‬ما به صورت دستی و برای خودمان یک استثناء ایجاد کردهایم‪ .‬ابتدا از کاربر‬
‫میخواهیم که دو مقدار را وارد کند (خطوط ‪ .)9-13‬سپس تفاوت دو عدد را محاسبه میکنیم (خط ‪ .)15‬در داخل بلوک ‪ try‬تست میکنیم که آیا حاصل تفریق‬
‫دو عدد‪ ،‬یک عدد منفی است (خط ‪ .)19‬اگر یک عدد منفی بود سپس یک نمونه از کالس ‪ NegativeNumberException‬ایجاد میکنیم (خط ‪ .)21‬بعد‬
‫از ایجاد نمونه به وسیله بلوک ‪ catch‬و برای نشان داده پیغام خطا آن را اداره میکنیم (خطوط ‪.)24-26‬‬

‫اشکال زدایی توسط ویژوال استودیو‬

‫‪208‬‬
‫اشکال زدایی فرایندی است که طی آن خطاها و باگ های برنامه شما تشخیص داده می شود‪ .‬اگر خطا های دستوری برنامه تان را با استفاده از پنجره ‪Error‬‬
‫‪ List‬برطرف کرده اید‪ ،‬مرحله بعد پیدا کردن خطاهای منطقی و استثناءها در هنگام اجرای برنامه است‪ .‬ویژوال استودیو و ویژوال سی شارپ دارای ابزارهای‬
‫هستند‪.‬‬ ‫زدایی‬ ‫اشکال‬ ‫برای‬ ‫کارامدی‬
‫با استفاده از این ابزارها می توانید برنامه را در نقاط خاصی (دلخواه) متوقف کرده و مقادیر هر یک از متغیرهایی را که توسط برنامه مورد استفاده قرار می گیرند را‬
‫مشاهده نمایید‪ .‬این کار را می ت وان به صورت گام به گام و خط به خط انجام داد‪ .‬می توانید استثناء را چک کرده و از طریق راهنمای ویژوال استودیو که در‬
‫درسهای آینده توضیح می دهیم مشکالت مربوط را برطرف کرد‪.‬‬

‫نقطه انفصال (‪)Breakpoints‬‬

‫‪ Breakpoints‬به شما اجازه میدهد که برنامهتان را در نقاط خاصی متوقف کنید‪ .‬برای این کار ‪ Breakpoints‬را در مکان از کدتان که میخواهید‬
‫اطالعاتی در مورد آن کسب کنید قرار میدهید‪ Breakpoints .‬را فقط میتوان در خطوط قابل اجرای کد قرار داد‪ .‬به وسیله این ابزار (‪)Breakpoints‬‬
‫میتوان برنامه را موقتاً متوقف کرده و سپس با استفاده از دیگر ابزارهای ویژوال استودیو آن را خطایابی کرد‪ .‬به وسیله برنامه زیر نحوه کار با ‪ Breakpoints‬را‬
‫به شما آموزش میدهیم‪ .‬یک برنامه کنسول ایجاد کرده و نام آن را ‪ Breakpoints‬بگذارید‪ .‬کدهای زیر را در برنامه وارد کنید ‪:‬‬

‫;‪using System‬‬

‫‪namespace Breakpoints‬‬
‫{‬
‫‪public class Program‬‬
‫{‬
‫)(‪public static void Main‬‬
‫{‬
‫;)"‪Console.WriteLine("Line 1‬‬
‫;)"‪Console.WriteLine("Line 2‬‬
‫;)"‪Console.WriteLine("Line 3‬‬
‫;)"‪Console.WriteLine("Line 4‬‬
‫;)"‪Console.WriteLine("Line 5‬‬
‫;)"‪Console.WriteLine("Line 6‬‬
‫;)"‪Console.WriteLine("Line 7‬‬
‫;)"‪Console.WriteLine("Line 8‬‬
‫;)"‪Console.WriteLine("Line 9‬‬
‫;)"‪Console.WriteLine("Line 10‬‬
‫}‬
‫}‬
‫}‬

‫اضافه کردن ‪Breakpoints‬‬


‫برای اضافه کردن ‪ ، Breakpoints‬یک خط کد اجرایی را پیدا کرده و بر روی حاشیه خاکستری رنگ سمت چپ کد (شکل زیر) کلیک کنید‪ .‬به عنوان مثال‬
‫اجازه دهید یک ‪ Breakpoints‬به دومین دستور )(‪ WriteLine‬اضافه کنیم‪.‬‬

‫‪209‬‬
‫همچنین میتوان بر روی کد مورد نظر کلیک راست کرده و از مسیر ‪ Insert Breakpoint > Breakpoints‬یک ‪ Breakpoints‬به آن اضافه کنید‪.‬‬
‫دستور یا خط کدی که دارای ‪ Breakpoint‬است با رنگ قرمز نشان داده میشود‪ .‬برای پاک کردن ‪ Breakpoint‬کافی است بر روی کدی که دارای‬
‫‪ Breakpoint‬است کلیک راست کرده و از مسیر ‪ Breakpoint‬گزینه ‪ Delete Breakpoint‬را انتخاب کنید‪ .‬همچنین میتوان بر روی کد مورد نظر‬
‫دکمه ‪ F9‬را برای فعال و غیر فعال کردن ‪ Breakpoint‬فشار داد‪ .‬میتوانید تعداد زیادی ‪ Breakpoint‬در قسمتهای مختلف کدتان قرار دهید‪ .‬حال به‬
‫هفتمین دستور )(‪ WriteLine‬هم یک ‪ Breakpoint‬اضافه کنید‪.‬‬

‫کلیک کنید‪ .‬به این‬ ‫برای مشاهده عملکرد ‪ Breakpoint‬برنامه را در حالت ‪ Debug‬به وسیله دکمه ‪ F5‬اجرا کنید و یا بر روی شکل‬
‫نکته توجه کنید که میتوان حالت ‪ Debug‬را با استفاده از دکمه آبی مربع شکلی که بعد از دکمه ‪( Debug‬فلش سبزرنگ) که در ‪ Toolbar‬قرار دارد متوقف‬
‫کرد‪ .‬وقتی که برنامه اجرا میشود بعد از رسیدن به اولین ‪ Breakpoint‬متوقف میشود‪.‬‬

‫‪210‬‬
‫در این حالت کدهای قبل از دومین دستور اجرا میشوند‪ .‬اگر به پنجره محیط کنسول نگاه کنید متوجه میشوید که اولین دستور )(‪ WriteLine‬اجرا شده است‪.‬‬
‫فلش زرد رنگ نشان میدهد که کد زرد رنگ متناظر با آن توسط برنامه اجرا شده است‪ .‬برای ادامه ‪ Breakpoint‬و تست کد بعدی دوباره فلش سبزرنگ واقع‬
‫در نوار ‪ Toolbar‬را فشار دهید‪ .‬همچنین میتوان از دکمه ‪ F5‬استفاده کرد یا از مسیر ‪ Debug‬گزینه ‪ Continue‬را انتخاب کنید‪.‬‬

‫ادامه به ‪ Breakpoint‬باعث اجرای همه کدهای بین دو ‪ Breakpoint‬مبدأ و ‪ Breakpoint‬مقصد میشود‪ .‬اگر به محیط کنسول نگاه کنید مشاهده‬
‫میکنید که همه خطهای قبل از هر ‪ Breakpoint‬اجرا میشوند‪ .‬فلش زرد رنگ هم با هر بار فشار دادن دکمه ‪ F5‬به ‪ BreakPoint‬های بعدی میرود‪.‬‬
‫بعد از اتمام ‪ BreakPoint‬ها برنامه نیز خود به خود بسته میشود‪ .‬برای غیر فعال کردن موقتی ‪ Breakpoint‬ها هم میتوانید با کلیک راست بر روی هر‬
‫دستور از مسیر ‪ Disable Breakpoint > Breakpoints‬این کار را انجام دهید‪ Breakpoint .‬غیر فعال با یک دایره توخالی نمایش داده میشود‪.‬‬
‫برای فعال کردن مجدد آن بر روی دستور کلیک راست کرده و از منوی باز شده گزینه ‪ Breakpoint‬و سپس ‪ Enable Breakpoint‬را انتخاب میکنید‪.‬‬
‫همچنین میتوان با قرار دادن نشانگر ماوس بر روی دستور دارای ‪ Breakpoint‬آن را فعال یا غیر فعال کرد‪.‬‬

‫قدم زدن در میان کدها‬


‫‪211‬‬
‫ یک برنامه کنسول جدید ایجاد کنید و‬.‫ می توان خط به خط کدها را مورد بررسی قرار داد و از تأثیر هر خط در برنامه مطلع شد‬BreakPoint ‫با استفاده از‬
: ‫کدهای زیر را در آن وارد نمایید‬

using System;

namespace SteppingThroughCode
{
public class MyClass
{
public static void ShowMessage()
{
Console.WriteLine("Hello World!");
Console.WriteLine("Have a nice day!");
}
}

public class Program


{
public static void Main()
{
Console.WriteLine("Line 1");
Console.WriteLine("Line 2");
Console.WriteLine("Line 3");

MyClass.ShowMessage();

for (int i = 0; i < 5; i++)


{
Console.WriteLine("Hi there!");
}
}
}
}

.‫) اضافه کنید‬18 ‫ (خط‬Main() ‫ در متد‬WriteLine() ‫ به اولین دستور‬breakpoint ‫یک‬

212
‫میتوانیم به شما نشان دهیم که چگونه میتوانید در میان بخشهای مختلف کدتان با استفاده از گزینههای ‪ Step Into ،Step Over‬و ‪ Step Out‬قدم‬
‫بزنید‪ .‬برنامهتان در حالت ‪ Debug‬به وسیله دکمه ‪ F5‬اجرا کنید‪ .‬برنامه در اولین ‪ breakpoint‬متوقف میشود‪ .‬اکنون میتوانیم چک کردن کدهایمان را از‬
‫این ‪ breakpoint‬شروع کنیم‪.‬‬

‫دستوراتی که به وسیله آنها میتوان تک تک بخشهای کدتان را تست کنید‪ ،‬در ‪ toolbar‬قرار دارند که به وسیله شکل زیر به شما نمایش داده شدهاند ‪:‬‬

‫باعث اجرای خط جاری برنامه در حال اجرا شده و سپس فلش زرد رنگ را به خط بعد میبرد‪ .‬حال اگر به محیط‬ ‫کلیک بر روی آیکون ‪Step Over‬‬
‫کنسول نگاهی بیندازید مشاهده میکنید که اولین دستور )(‪ WriteLine‬اجرا شده است‪.‬‬

‫‪213‬‬
‫تکرار این کار (زدن بر روی آیکون ‪ Step Over‬باعث اجرای تمام کدها میشود‪ .‬کلیک بر روی آیکون ‪ Step Over‬را تا جایی ادامه دهید که به خط‬
‫)(‪MyClass.ShowMessage‬برسید‪.‬‬

‫‪ .‬این دستور وارد متد انتخاب شده میشود (شما را به محل تعریف متد میبرد‪ ).‬و جزئیاتی در مورد آن در اختیار‬ ‫حال از دستور ‪ Step Into‬استفاده میکنیم‬
‫شما قرار میدهد و شما را قادر میسازد که خطهای داخل متد را یک به یک اجرا کنید‪:‬‬

‫‪214‬‬
‫‪ .‬استفاده از دستور‬ ‫با استفاده از دستور ‪ Step Over‬به خطهای بعدی متد بروید و برای خروج از متد هم میتوان از دستور ‪ Step Out‬استفاده کرد‬
‫‪ Step Out‬باعث اجرای بخشهای باقیمانده متد شده و به محل فراخوانی متد میرود (شکل زیر) ‪:‬‬

‫با کلیک دوباره بر روی دکمه ‪ Step Over‬وارد حلقه ‪ for‬میشوید‪ .‬با هر بار زدن این دکمه هم شرط تست میشود هم حلقه اجرا میشود و هم شمارنده‬
‫افزایش مییابد‪ .‬اگر شرط درست باشد شما وارد حلقه و اگر نادرست باشد وارد دستور بعد میشوید‪ .‬وارد شدن به کدها بدون دانستن اینکه چگونه آنها را تست‬
‫کنید بی فایده است‪ .‬در درس بعد به شما نحوه به دست آوردن مقادیر متغیرها و اعضای یک شیء را آموزش میدهیم‪.‬‬

‫به دست آوردن مقادیر متغیرها‬

‫در حالت ‪ Debug‬می توان به قسمت کدنویسی رفته و مقدار و حاالت اشیا و متغیرها را مورد بررسی قرار داد‪ .‬همانطور که قبالً ذکر شد‪ ،‬میتوان از‬
‫‪ breakpoint‬برای جلوگیری موقت از اجرای برنامه و امتحان کردن کدهای آن استفاده کرد‪ .‬ویژوال استودیو و ویژوال سی شارپ دارای ابزارهایی هستند که‬
‫به شما نحوه اجرای برنامهها را نشان میدهند‪ .‬برنامه کنسول ایجاد کنید و نام آن را ‪ DebuggingTechniques‬بگذارید‪ .‬کد زیر را به برنامه اضافه کنید ‪:‬‬

‫;‪using System‬‬

‫‪namespace DebuggingTechniques‬‬
‫{‬

‫‪public class Person‬‬

‫‪215‬‬
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }

public Person() : this("", "", 0) { }

public Person(string fn, string ln, int a)


{
FirstName = fn;
LastName = ln;
Age = a;
}
}

public class Program


{
static void Main()
{
Person firstPerson = new Person ("John", "Smith", 20);
Person secondPerson = new Person();
string firstName;
string lastName;
int age;

firstName = "Mike";
lastName = "Welsh";
age = 30;

secondPerson.FirstName = firstName;
secondPerson.LastName = lastName;
secondPerson.Age = age;

Console.WriteLine("First Person Details: ");


Console.WriteLine("First Name: {0}", firstPerson.FirstName);
Console.WriteLine("Last Name: {0}", firstPerson.LastName);
Console.WriteLine("Age: {0}n", firstPerson.Age);

Console.WriteLine("Second Person Details: ");


Console.WriteLine("First Name: {0}", secondPerson.FirstName);
Console.WriteLine("Last Name: {0}", secondPerson.LastName);
Console.WriteLine("Age: {0}", secondPerson.Age);
}
}
}

‫ برنامه‬.‫ حال به شما نشان میدهیم که چطور مقادیر موجود در متغیرها و اشیا را مشاهده کنید‬.‫ اضافه کنید‬Main)( ‫ به اولین خط کد در متد‬break point ‫یک‬
‫ متوقف می شود نشانگر ماوس را بر روی هر شی یا متغیر که ببرید یک پنجره کوچک ظاهر‬breakpoint ‫ برنامه در اولین‬.‫ اجرا کنید‬Debug ‫را در حالت‬
.‫میشود که شامل نام و مقدار موجود در آن شیء یا متغیر میباشد‬

216
‫مقدار جاری شی ‪ firstPerson‬تهی است‪ ،‬چون هنوز هیچ مقداری به آن اختصاص داده نشده است‪ .‬خط زرد رنگ هنوز اجرا نشده است‪ .‬در پنجره کوچکی که‬
‫با فلش نشان داده شده است‪ ،‬یک آیکون سنجاق مانند مشاهده میکنید‪ .‬با کلیک بر روی این آیکون پنجره کوچک دیگر به صورت خودکار بسته نمیشود‪ .‬برای‬
‫اینکه پنجره کوچک دوباره به صورت عادی برگردد و به صورت خودکار مخفی شود کافیست بار دیگر بر روی آیکون مذکور کلیک کنید‪ .‬اگر ماوس را برای‬
‫لحظه ای بر روی یک نوع یا یک کالس قرار دهید (متوقف کنید)‪ ،‬جزییاتی در مورد آنها از قبیل سلسله مراتب وراثت را مشاهده میکنید‪.‬‬

‫بر روی آیکون ‪ Step Over‬کلیک کرده تا کد جاری اجرا شود و فلش زرد رنگ به خط بعد برود‪ .‬از آنجاییکه خط کد قبل اجرا شده است‪ firstPerson ،‬به‬
‫وسیله سازندهاش مقداردهی اولیه شده است‪ .‬اگر ماوس را بر روی شیء ‪ firstPerson‬برای لحظهای قرار دهید یک پنجره ظاهر میشود (پنجره ‪)DataTip‬‬
‫که شامل مقادیر و نام کامل کالس آن است‪ .‬همچنین یک آیکون ‪ +‬در سمت چپ آن مشاهده خواهید کرد که با کلیک بر روی آن همه خواص و فیلدهای شیء‬
‫جاری و مقادیر مربوط به آنها نمایش داده خواهد شد‪.‬‬

‫‪217‬‬
‫همچنین آیکون یک ذره بین را در کنار برخی از اعضا مشاهده میکنید که با کلیک بر روی آن تمام محتویات یک متغیر حتی اگر بزرگ باشد به شما نشان داده‬
‫خواهد شد (شکل زیر)‪.‬‬

‫با کلیک بر روی مقادیر در پنجره ‪ DataTip‬میتوان آنها را تغییر داد‪ .‬به عنوان مثال بر روی مقدار فیلد ‪ FirstName‬کلیک کنید و آن را از ‪ John‬به‬
‫‪ Joseph‬تغییر داده و سپس کلید ‪ enter‬را فشار دهید‪.‬‬

‫پنجره ‪Locals‬‬

‫‪218‬‬
‫پنجره ‪ Locals‬مکانی است که در آن میتوانید همه مقادیر مربوط به متغیرها و اشیا را که به وسیله برنامه مورد استفاده قرار میگیرند‪ ،‬مشاهده کنید‪ .‬این پنجره‬
‫به صورت خودکار وقتی که برنامه را در حالت ‪ Debug‬اجرا میکنید نمایش داده میشود‪ .‬مکان این پنجره همانطور که در شکل زیر نمایش داده شده است در‬
‫قسمت پایین سمت چپ محیط ویژوال استودیو قرار دارد‪ .‬تا وقتی که به اولین دستور ()‪ WriteLine‬میرسید بر روی آیکون ‪ Step Over‬کلیک کنید‪ .‬حال‬
‫به پنجره ‪ Locals‬که با فلش نشان داده شده است نگاه کنید‪:‬‬

‫لیستی از همه متغیرهایی که مورد استفاده قرار گرفتهاند را مشاهده میکنید‪ .‬این پنجره شامل سه ستون به نامهای ‪ Value،Name‬و ‪ Type‬میباشد‪ .‬برای‬
‫انواع پیچیده مانند کالسها یک آیکون ‪ +‬در سمت چپ نام آنها قرار دارد که با کلیک بر روی آن اعضای کالس و مقادیر آنها نشان داده میشود‪ .‬میتوان با دو بار‬
‫کلیک کردن بر روی مقادیر متغیرها در پنجره ‪ Locals‬آنها را تغییر داد‪.‬‬

‫پنجره ‪Watch‬‬

‫پنجره ‪ Watch‬اجازه تایپ نام متغیرها و مشاهده مقادیر آنها را میدهد‪ .‬این پنجره حتی به شما اجازه میدهد دو متغیر مقداری را به وسیله عملگرهای ریاضی با‬
‫هم جمع یا … کنید‪ .‬این پنجره همانطور که در شکل مشاهده میکنید در کنار پنجره ‪ Locals‬قرار دارد‪.‬‬

‫‪219‬‬
‫میتوانید نام متغیری که مد نظرتان است را در ستون ‪ Name‬تایپ کرده و سپس کلید ‪ enter‬را فشار دهید با این کار مقدار متغیر در ستون ‪ Value‬نمایش‬
‫داده خواهد شد‪ .‬همچنین میتوانید به عنوان مثال در ستون ‪ Name‬یک مقدار ثابت را با مقدار یک متغیر که در برنامه وجود دارد جمع کرده و نتیجه را مشاهده‬
‫کنید‪.‬‬

‫کلکسیون ها (‪) Collections‬‬

‫قبالً یاد گرفتیم که آرایهها به ما اجازه ذخیره چندین مقدار از یک نوع را میدهند‪ .‬آرایهها از کالس مجرد ‪ System.Array‬ارث بری میکنند که این کالس‬
‫دارای خواص و متدهایی برای کار با دادههای سادهای مانند طول آرایه میباشد‪ .‬آرایههای ساده در سی شارپ دارای طول ثابتی هستند که یک بار تعریف و‬
‫دهید‪.‬‬ ‫کاهش‬ ‫یا‬ ‫افزایش‬ ‫را‬ ‫خاص‬ ‫آرایه‬ ‫یک‬ ‫طول‬ ‫نمیتوانید‬ ‫شما‬ ‫و‬ ‫میشوند‬ ‫مقداردهی‬
‫دات نت گزینه بهتری برای جایگزین کردن با آرایهها پیشنهاد میدهد و بیشتر آنها کالسها و رابطهایی هستند که‪ ،‬در فضای نام ‪System.Collections‬‬
‫قرار دارند‪ .‬به عنوان مثال کالس ‪ ArrayList‬رفتاری شبیه به یک آرایه معمولی دارد با این تفاوت که به شما اجازه میدهد که طول آن را به صورت پویا تغییر‬
‫داده یا یک عنصر را در طول اجرای برنامه به آن اضافه کرده و یا از آن حذف نمایید‪ .‬در درس بعد پی میبرید که چگونه یک کالس که شامل مجموعهای از‬
‫اشیاء است را به وسیله اجرا کردن و یا ارث بری از رابطها و متدها ایجاد کنیم‪.‬‬

‫کالس ‪ArrayList‬‬

‫کالس ‪ ArrayList‬به شما اجازه ذخیره مقادیر انواع دادهای مختلف‪ ،‬و توانایی حذف و اضافه عناصر آرایه در هر لحظه را میدهد‪ .‬در مثال زیر به سادگی کاربرد‬
‫کالس ‪ ArrayList‬آمده است‪.‬‬

‫;‪using System‬‬
‫;‪using System.Collections‬‬

‫‪public class Program‬‬


‫{‬
‫)(‪public static void Main‬‬
‫‪220‬‬
‫{‬
‫;)(‪ArrayList myArray = new ArrayList‬‬

‫;)"‪myArray.Add("John‬‬
‫;)‪myArray.Add(5‬‬
‫;)‪myArray.Add(true‬‬
‫;)‪myArray.Add(3.65‬‬
‫;)'‪myArray.Add('R‬‬

‫)‪foreach (object element in myArray‬‬


‫{‬
‫;))(‪Console.WriteLine(element.ToString‬‬
‫}‬
‫}‬
‫}‬

‫‪John‬‬
‫‪5‬‬
‫‪true‬‬
‫‪3.65‬‬
‫‪R‬‬
‫برای استفاده از این کالس ابتدا باید در قسمت فضاهای نامی‪ ،‬فضای نام ‪ System.Collections‬را وارد کنیم (خط ‪ .)2‬همانطور که در مثال مشاهده‬
‫میکنید یک نمونه از کالس ‪ ArrayList‬ایجاد میکنیم‪ .‬برای اضافه کردن یک عنصر به آرایه باید از متد ()‪ Add‬استفاده کنیم‪ .‬از آنجاییکه شی ایجاد شده از‬
‫کالس ‪ ArrayList‬آرگومانی از نوع ‪ object‬قبول میکند بنابراین میتوان مقادیری از هر نوع دادهای به آن ارسال کرد چون هر چیز در سی شارپ از‬
‫‪ object‬ارث بری میکند‪.‬‬
‫حال برای نمایش توانایی این کالس در نگهداری انواع دادهای مختلف پنج مقدار از پنج نوع مختلف داده را به آن اضافه میکنیم‪ .‬سپس همه مقادیر را با استفاده‬
‫از دستور ‪ foreach‬میخوانیم‪ .‬چون کالس ‪ ArrayList‬دارای انواع دادهای مختلفی است نمیتوانیم از یک نوع دادهای خاص برای خواندن مقادیر استفاده‬
‫کنیم‪ .‬لذا برای این کار باید از نوع ‪ object‬که میتواند هر نوع دادهای در خود ذخیره کند استفاده نمود‪ .‬در داخل حلقه از متد ()‪ ToString‬برای نشان دادن‬
‫مقادیر استفاده کردهایم‪ .‬به این نکته توجه کنید که برای دسترسی به هر عنصر میتوانید از طریق اندیس آن قدام نمایید‪ .‬کد زیر نحوه استفاده از حلقه ‪ for‬برای‬
‫دسترسی به هر یک از اعضا را نشان میدهد‪.‬‬

‫)‪for (int i = 0; i < myArray.Count; i++‬‬


‫{‬
‫;))(‪Console.WriteLine(myArray[i].ToString‬‬
‫}‬

‫به خاصیت ‪ Count‬در کد باال توجه کنید‪ .‬این خاصیت درست شبیه به خاصیت ‪ Length‬آرایه معمولی است و کار آن شمارش تعداد عناصرشی ‪ArrayList‬‬
‫میباشد‪ ..‬در کد باال همانطور که نشان داده شده است میتوان به هر یک از عناصر با استفاده از اندیسشان دست یافت‪ .‬نکته دیگر این است که شما میتوانید به‬
‫کالس ‪ ArrayList‬یک ظرفیت ابتدایی بدهید‪ .‬به عنوان مثال شما میتوانید با استفاده از یک سازنده سربارگذاری شده نشان دهید که یکشی ‪ArrayList‬‬
‫میتواند دارای ‪ 5‬عنصر باشد‪.‬‬

‫;)‪ArrayList myArray = new ArrayList(5‬‬

‫کد باال ‪ 5‬مکان خالی به وجود میآورد و شما میتوانید با استفاده از متد ()‪ Add‬یکی دیگر به آنها اضافه کنید‪ .‬اگر همه مکانها به وسیله مقادیر پر شوند میتوان‬
‫سایزشی ایجاد شده از کالس ‪ ArrayList‬را با استفاده از تغییر خاصیت ‪ Capacity‬آن تغییر داد‪ .‬یکی دیگر از نسخههای سازنده کالس ‪ArrayList‬‬
‫شیئی که رابط ‪ Icollection‬را اجرا میکند را قبول میکند‪ System.Array .‬مثالی از این شیء است‪ .‬بنابراین شما یک آرایه را به سازنده ارسال میکنید و‬
‫مقادیر آن آرایه در شیء ‪ ArrayList‬کپی میشوند‪.‬‬
‫‪221‬‬
object[] array = {"John", 5, true, 3.65, 'R' };

ArrayList myArray = new ArrayList(array);

‫ یک شیء که مطابق مقدار یک عنصر در آرایه است را قبول‬Remove)( ‫ متد‬.‫ عناصر را پاک کرد‬ArrayList ‫ کالس‬Remove)( ‫میتوان با استفاده از متد‬
‫ اگر عنصری را که مکانی غیر از مکان آخر آرایه باشد حذف کنید بقیه عناصر بعد از آن‬.‫ این متد به محض رسیدن به مقدار مورد نظر آن را حذف میکند‬.‫میکند‬
‫ در این صورت جای خالی این‬،‫ را حذف میکنید‬3 ‫ عنصر است و شما عنصر‬5 ‫عنصر مکان خود را تنظیم میکنند به این معنی که فرض کنید آرایهای دارای‬
: ‫ به تکه کد زیر توجه کنید‬.‫ پر میشود‬5 ‫ توسط عنصر‬4 ‫ و جای عنصر‬4 ‫عنصر توسط عنصر‬

using System;
using System.Collections;

public class Program


{
public static void Main()
{
ArrayList myArray = new ArrayList();

myArray.Add("John");
myArray.Add(5);
myArray.Add(true);
myArray.Add(3.65);
myArray.Add('R');

for (int i = 0; i < myArray.Count; i++)


{
Console.WriteLine("myArray[{0}] = {1}", i, myArray[i]);
}

//Remove element number 1


myArray.Remove(5);

Console.WriteLine("nAfter removing myArray[1] (The value 5)...n");

for (int i = 0; i < myArray.Count; i++)


{
Console.WriteLine("myArray[{0}] = {1}", i, myArray[i]);
}
}
}

myArray[0] = John
myArray[1] = 5
myArray[2] = True
myArray[3] = 3.65
myArray[4] = R

After removing myArray[1] (The value 5)...

myArray[0] = John
myArray[1] = True

222
‫‪myArray[2] = 3.65‬‬
‫‪myArray[3] = R‬‬
‫از آنجاییکه در مثال باال مقدار عنصر ]‪ myArray[1‬را حذف کردهایم همه عناصر متوالی در آرایه باال مکان خود را تغییر میدهند‪ .‬بنابراین عنصر‬
‫]‪ myArray[2‬جای ]‪ ،myArray[1‬عنصر ]‪ myArray[3‬جای ]‪ myArray[2‬و …را میگیرد‪ .‬شما همچنین میتوانید با استفاده از متد‬
‫()‪ RemoveAt‬به اندیس آرایه خاصی دست یافته و آن را حذف نمایید‪ .‬این متد یک پارامتر قبول میکند و آن اندیس عنصری است که میخواهید از آرایه‬
‫حذف کنید‪.‬‬

‫حذف و اضافه کردن چند آیتم‬

‫میتوان با استفاده از متدهای ()‪ AddRange‬و ()‪ RemoveRange‬چندین آیتم را از آرایه حذف یا به آن اضافه نمود‪ .‬متد ()‪ AddRange‬میتواند‬
‫آرایهای از چند مقدار را گرقته و آنها را به شی ‪ ArrayList‬اضافه کند‪.‬‬

‫;)(‪ArrayList myArray = new ArrayList‬‬

‫;)‪myArray.Add(1‬‬
‫;)‪myArray.Add(2‬‬

‫;} ‪int[] numbers = { 3, 4, 5‬‬

‫;)‪myArray.AddRange(numbers‬‬

‫)‪foreach(object element in myArray‬‬


‫{‬
‫;)‪Console.WriteLine(element‬‬
‫}‬

‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪5‬‬
‫متد ()‪ RemoveRange‬کامالً با متد ()‪ AddRange‬متفاوت است‪ .‬این متد دو پارامتر قبول میکند‪ ،‬اندیس عنصری که فرایند حذف از آن شروع میشود و‬
‫تعداد عناصری که میخواهیم حذف کنیم‪ .‬به عنوان مثال اگر بخواهید عناصر ‪ 2‬تا ‪ 6‬را حذف کنید باید تکه کد زیر را بنویسید ‪:‬‬

‫;)‪myArray.RemoveRange(2, 5‬‬

‫جستجوی مقادیر‬

‫با استفاده از متد ()‪ Contains‬می توان چک کرد که آیا یک مقدار خاص در داخل آرایه وجود دارد یا خیر‪ .‬این متد یک آرگومان از نوع شیء را قبول کرده و اگر‬
‫یک مقدار را در داخل لیست عناصر پیدا کند ‪ true‬را بر میگرداند‪ ،‬از متدهای ()‪ IndexOf‬و ()‪ LastIndexOf‬برای تشخیص اندیس یک مقدار خاص‬
‫استفاده میشود‪.‬‬
‫متد ()‪ IndexOf‬اندیس اولین محل وقوع یک مقدار خاص را بر میگرداند‪.‬‬
‫متد ()‪ LastIndexOf‬اندیس آخرین محل وقوع یک مقدار خاص را بر میگرداند‪.‬‬

‫‪223‬‬
‫هر دو متد‪ ،‬در صورتیکه مقدار مورد نظر را پیدا نکنند مقدار ‪ -1‬را بر میگردانند‪.‬‬
‫متد ()‪ BinarySearch‬هم میتوان برای جستجوی یک مقدار استفاده نمود‪ .‬البته این متد برای جستجو یک عنصر در داخل تعداد زیادی از عناصر مناسب‬
‫است‪.‬‬

‫مرتب سازی مقادیر ‪ArrayList‬‬

‫با استفاده از متد ‪ Sort‬میتوان مقادیر یک آرایه را مرتب نمود‪ .‬اعداد از بزرگ به کوچک و رشته بر اساس حروف الفبا مرتب میشوند‪ .‬اگر از این متد استفاده‬
‫کنید همه اجزا با هم مقایسه میشوند‪ .‬به عنوان مثال نمیتوان یک رشته و یک عدد از نوع ‪ int‬را در داخل ‪ ArrayList‬قرار داد و آنها را با متد ()‪ Sort‬مرتب‬
‫نمود‪ .‬در درس آینده یاد خواهید گرفت که چگونه از یک مقایسه گر سفارشی برای مرتب کردن عناصر استفاده نمود‪.‬‬

‫ایجاد یک کلکسیون‬

‫سی شارپ به شما توانایی ایجاد کلکسیون ی از کالس ها را می دهد‪ .‬به عنوان مثال می توان کالسی ایجاد کرد که شامل چندین نمونه از کالس های دیگر‬
‫باشد‪ .‬این کالس خصوصیاتی مانند حذف و اضافه نمونه ها از کلکسیون را دارا می باشد‪ .‬به مثال زیر توجه کنید ‪:‬‬

‫;‪using System.Collections‬‬

‫‪public class Animal‬‬


‫{‬
‫} ;‪public string Name { get; set‬‬
‫} ;‪public int Age { get; set‬‬
‫} ;‪public double Height { get; set‬‬

‫)‪public Animal(string name, int age, double height‬‬


‫{‬
‫;‪Name = name‬‬
‫;‪Age = age‬‬
‫;‪Height = height‬‬
‫}‬
‫}‬

‫‪public class Animals : CollectionBase‬‬


‫{‬
‫)‪public void Add(Animal newAnimal‬‬
‫{‬
‫;)‪List.Add(newAnimal‬‬
‫}‬

‫)‪public void Remove(Animal oldAnimal‬‬


‫{‬
‫;)‪List.Remove(oldAnimal‬‬
‫}‬
‫}‬

‫در مثال باال دو کالس تعریف شده است‪ .‬اولین کالس‪ ،‬کالس ‪ Animal‬است که یک عنصر از کلکسیون کالسمان است‪ .‬دومین کالس‪ ،‬کلکسیون کالسمان‬
‫است (‪ )Animals‬که شامل مجموعه ای از اشیاء کالس ‪ Animal‬می باشد‪ .‬برای استفاده بهتر از کاربرد کلکسیون ها‪ ،‬کالسمان از کالس‬
‫‪224‬‬
‫ کالس‬.‫ را قسمت تعریف فضاهای نامی وارد کنید‬System.Collections ‫ به این نکته توجه کنید که فضای نام‬.‫ ارث بری می کند‬CollectionBase
‫ برای حذف یا‬.‫ می باشد‬،‫ که مجموعه ای از اشیاء را در خود جای می دهد‬List ‫ و خاصیت‬Remove)( ‫ و‬Add)( ‫ دارای متدهایی مانند‬CollectionBase
‫بنابراین‬.‫ یک شیء قبول می کنند نه یک کالس‬List ‫ متدهای خاصیت‬.‫ و متد مربوطه استفاده نمود‬List ‫اضافه کردن اشیاء به سادگی می توان از خاصیت‬
.‫ نتیجه را تبدیل و سپس آن را به کاربر برگشت دهیم‬cast ‫وقتی که یک ایندکسر تعریف می کنیم الزم است که ابتدا با استفاده از عمل‬

public Animal this[int index]


{
get { return (Animal)List[index]; }
set { List[index] = value; }
}

‫ شی قبول می کند الزم است که‬،List ‫ از آنجاییکه خاصیت‬.‫با استفاده از کد باال می توانیم به هر یک از اشیاء کلکسیون بوسیله اندیس مکانشان دسترسی یابیم‬
: ‫ به برنامه زیر توجه کنید‬.‫ تبدیل کنیم‬Animal ‫ آنها را به اشیاء‬cast ‫با استفاده از عمل‬

public class Program


{
public static void Main()
{
Animals animalCollection = new Animals();

animalCollection.Add(new Animal("Jack", 10, 100));


animalCollection.Add(new Animal("Sussy", 5, 10));
animalCollection.Add(new Animal("Frank", 3, 5));

for (int i = 0; i < animalCollection.Count; i++)


{
Console.WriteLine("Animal {0}", i + 1);
Console.WriteLine("Name: {0}", animalCollection[i].Name);
Console.WriteLine("Age: {0}", animalCollection[i].Age);
Console.WriteLine("Height: {0}n", animalCollection[i].Height);
}
}
}

Animal 1
Name: Jack
Age: 10
Height: 100

Animal 2
Name: Sussy
Age: 5
Height: 10

Animal 3
Name: Frank
Age: 3
Height: 5

225
‫در برنامه باال یک نمونه از کالس )‪ Animals (animalCollection‬و سپس سه نمونه به آن با استفاده از متد ()‪ Add‬اضافه کرده ایم‪.‬سپس با گردش‬
‫در میان عناصر با استفاده از یک حلقه نشان داده ایم که می توان با استفاده از اندیس به آنها دست یافت‪ .‬این کار را با استفاده از یک حلقه ‪ foreach‬هم می‬
‫توان انجام داد‪:‬‬

‫)‪foreach (Animal animal in animalCollection‬‬


‫{‬

‫}‬

‫در درس آینده با ‪ generic‬ها آشنا می شوید‪ ،‬که راهی آسان برای ایجاد کلکسیونی از هر نوع ‪ ،‬بدون ایجاد کالسی که از کالس پایه ‪CollectionBase‬‬
‫ارث بری کند‪ ،‬می باشد‪.‬‬

‫ساخت دیکشنری‬

‫می توان یک کالس ایجاد کرد که از کالس ‪ DictionaryBase‬مشتق شود‪ .‬با این روش شما می توانید به هر عنصر با استفاده از یک کلید (‪( )key‬که‬
‫معموال از نوع رشته است) دسترسی یابید‪ .‬این کلیدها دارای یک مقدار (‪ )value‬وابسته به خود هستند‪ .‬برای فراخوانی هر یک از آیتم های دیکشنری از کلید آن‬
‫استفاده می کنیم نه از اندیس آن‪.‬‬
‫به کد زیر توجه کنید ‪:‬‬

‫;‪using System.Collections‬‬

‫‪public class Animal‬‬


‫{‬
‫} ;‪public string Name { get; set‬‬
‫} ;‪public int Age { get; set‬‬
‫} ;‪public double Height { get; set‬‬

‫)‪public Animal(string name, int age, double height‬‬


‫{‬
‫;‪Name = name‬‬
‫;‪Age = age‬‬
‫;‪Height = height‬‬
‫}‬
‫}‬

‫‪public class Animals : DictionaryBase‬‬


‫{‬
‫)‪public void Add(string key, Animal newAnimal‬‬
‫{‬
‫;)‪Dictionary.Add(key, newAnimal‬‬
‫}‬

‫)‪public void Remove(string key‬‬


‫{‬
‫;)‪Dictionary.Remove(key‬‬
‫}‬

‫]‪public Animal this[string key‬‬


‫‪226‬‬
{
get { return (Animal)Dictionary[key]; }
set { Dictionary[key] = value; }
}
}

Animals ‫ سپس یک کالس به نام‬.)3-15 ‫ تعریف کرده ایم که قرار است در کالس دیکشنری مورد استفاده قرار بگیرد(خطوط‬Animal ‫یک کالس به نام‬
‫ حال می توان متدهایی‬.‫ ارث بری می کند‬DictionaryBase ‫ است)که از کالس‬Animals ‫ و دیگری‬Animal ‫ایجاد می کنیم (نام یکی از کالس ها‬
‫ که می خواهیم به دیکشنری اضافه کنیم‬Animal ‫ به یک کلید از نوع رشته و یک شی‬Add)( ‫ متد‬.‫برای حذف و اضافه ورودی های دیکشنری تعریف کرد‬
‫ فقط به‬Remove)( ‫ متد‬.‫ برای اضافه کردن یک ورودی به دیکشنری استفاده می کنیم‬DictionaryBase ‫ کالس‬Dictionary ‫ از خاصیت‬.‫احتیاج دارد‬
‫ ما یک ایندکسر تعریف کرده‬.‫ برای حذف آیتم ها استفاده می کنیم‬Dictionary ‫ در این متد هم از خاصیت‬.‫کلید شی ایی که می خواهیم حذف کنیم نیاز دارد‬
.‫ اجازه بدهید برای نشان دان توانایی های کالس دیکشنری مان یک کالس ایجاد کنیم‬.‫ یک کلید از نوع رشته قبول می کند‬، int ‫ایم که به جای یک مقدار‬

using System;

public class Program


{
public static void Main()
{
Animals animalDictionary = new Animals();

animalDictionary.Add("Animal1", new Animal("John", 10, 100));


animalDictionary.Add("Animal2", new Animal("Sussy", 5, 10));
animalDictionary.Add("Animal3", new Animal("Frank", 3, 5));
animalDictionary.Add("Animal4", new Animal("Mark", 7, 15));

Console.WriteLine("Accessing entries by their keys");

for (int i = 0; i < animalDictionary.Count; i++)


{
Console.WriteLine(animalDictionary["Animal" + (i + 1)].Name);
}

animalDictionary.Remove("Animal3");
Console.WriteLine("nFrank was removed from the dictionary.");

Console.WriteLine("nIterating using foreach loop.");


foreach (DictionaryEntry animal in animalDictionary)
{
Console.WriteLine((animal.Value as Animal).Name);
}
}
}

Accessing entries by their keys


John
Sussy
Frank
Mark
227
‫‪Frank was removed from the dictionary.‬‬

‫‪Iterating using foreach loop.‬‬


‫‪John‬‬
‫‪Mark‬‬
‫‪Sussy‬‬
‫یک نمونه جدید از کالس دیکشنری ‪ Animals‬ایجاد می کنیم‪ .‬سپس چند نمونه از کالس ‪ Animal‬و کلیدهای مربوط به آنها را به آن اضافه می کنیم‪.‬‬
‫همانطور که در مثال باال مشاهده می کنید می توانیم با استفاده از حلقه ‪ for‬به هر یک از ورودی با استفاده از کلیدشان که حکم اندیس دارد دست یابیم‪ .‬سپس‬
‫با استفاده از متد ()‪ Remove‬سومین ورودی دیکشنری را با استفاده از کلیدش حذف کرده ایم‪ .‬و بعد مقادیر را با استفاده از یک حلقه ‪ foreach‬می خوانیم و‬
‫چاپ می کنیم‪ .‬شما باید به یک تفاوت توجه کنید‪ .‬ما از ‪ DictionaryEntry‬به عنوان نوع استفاده کرده ایم چون هر آیتم در کالس ‪ dictionary‬یک نوع‬
‫دارد‪ .‬شی واقعی در داخل خاصیت ‪ Value ،DictionaryEntry‬قرار دارد‪ .‬این مقدار را با استفاده از عمل ‪ cast‬به نوع مناسب تبدیل می کنیم‪.‬‬

‫‪Hashtable‬‬
‫از ‪ Hashtable‬زمانی استفاده می شود که بخواهید اطالعات را بر اساس کلید‪ /‬مقدار ذخیره کنید‪ .‬به عنوان مثال نام دانش آموز و نمره او در‬
‫امتحان‪ Hashtable.‬به شما اجازه تلفیق متن و عدد را می دهد‪ .‬یک پروژه جدید ایجاد کنید‪ .‬با زدن دکمه ‪ F7‬به محیط کدنویسی رفته و در باالی کدها و در‬
‫قسمت تعریف فضای نام‪ ،‬فضای نام زیر را وارد کنید ‪:‬‬

‫;‪using System.Collections‬‬

‫‪ Hashtable‬در این فضای نام قرار دارد‪ .‬کد زیر را هم در داخل متد ‪ Main‬وارد کنید‪.‬‬

‫;)(‪Hashtable students = new Hashtable‬‬

‫کد باال یک شئ به نام ‪ students‬ایجاد می کند‪ .‬دو راه برای اضافه کردن داده ها به ‪ Hashtable‬وجود دارد‪ .‬این دو روش در زیر نشان داده شده اند ‪:‬‬

‫;‪students["Jenny"] = 87‬‬
‫;"‪students["Peter"] = "No Score‬‬
‫;‪students["Mary Jane"] = 64‬‬
‫;‪students["Azhar"] = 79‬‬

‫یا‬

‫;)‪students.Add("Jenny", 87‬‬
‫;)"‪students.Add("Peter", "No Score‬‬
‫;)‪students.Add("Mary Jane", 64‬‬
‫;)‪students.Add("Azhar", 79‬‬

‫در روش اول از براکت استفاده شده است ‪:‬‬

‫;‪students["Jenny"] = 87‬‬

‫‪228‬‬
‫در داخل براکت ها کلید را تایپ می کنید‪ .‬که در این مورد خاص “‪ ”jenny‬می باشد‪ .‬سپس بعد از عالمت مساوی مقدار کلید را می نویسید‪ .‬به این نکته توجه‬
‫کنید که سه ورودی باال دارای مقدار عددی بوده به جز ‪ Peter‬که دارای مقدار متنی می باشد‪ .‬در روش دوم مقادیر یا استفاده از متد ‪ Add‬در ‪Hashtable‬‬
‫ذخیره می شوند‪:‬‬

‫;)‪students.Add("Jenny", 87‬‬

‫در بین دو پرانتز ()‪ ،Add‬ابتدا نام کلید سپس کاما و بعد از کاما مقدار کلید را می نویسید‪ .‬تفاوتی بین این دو وجود دارد‪ .‬اگر از متد ()‪ Add‬استفاده کنید نمی‬
‫توانید از کلیدهای مشابه استفاده کنید‪ .‬اما هنگام استفاده از براکت می شود‪ ،‬پیغام خطا می دهد ‪:‬‬

‫;)‪students.Add("Jenny", 87‬‬
‫;)‪students.Add("Jenny", 35‬‬

‫پیغام خطا نمی دهد ‪:‬‬

‫;‪students["Jenny"] = 87‬‬
‫;‪students["Jenny"] = 35‬‬

‫حال در زیر شئ ایجاد شده کدهای زیر را هم اضافه کنید‪:‬‬

‫;)(‪Hashtable students = new Hashtable‬‬


‫;‪students["Jenny"] = 87‬‬
‫;"‪students["Peter"] = "No Score‬‬
‫;‪students["Mary Jane"] = 64‬‬
‫;‪students["Azhar"] = 79‬‬

‫)‪foreach (DictionaryEntry child in students‬‬


‫{‬
‫;)‪Console.WriteLine("student: " + child.Key + " , Score: " + child.Value‬‬
‫}‬

‫قبل از اجرای کد به حلقه ‪ foreach‬توجه کنید‪ .‬در داخل پرانتزها از دستور زیر استفاده کرده ایم ‪:‬‬

‫‪DictionaryEntry child‬‬

‫کد باال یک متغیر به نام ‪ child‬را که نوع آن یک ‪ DictionaryEntry‬می باشد ایجاد می کند‪ .‬سی شارپ با استفاده از یک شی از این نوع در هنگام کار با‬
‫‪ ،Hashtable‬مقادیر و کلید ها را برگشت می دهد‪ .‬در مثال فوق مقادیر و کلید ها را در داخل کنترل ‪ listbox‬نشان می دهیم‪.‬‬

‫‪"student: " + child.Key + " , Score: " + child.Value‬‬

‫بعد از نوشتن نام متغیرمان ‪ (child)،IntelliSense‬ظاهر می شود‪ Key .‬خاصیتی است که نام کلید و ‪ Value‬خاصیتی است که مقدار کلید را برگشت می‬
‫دهد‪ .‬نتیجه اجرای برنامه به صورت زیر است ‪:‬‬
‫‪student: Mary Jane , Score:64‬‬
‫‪student: Jenny , Score:87‬‬
‫"‪student: Peter , Score: "No Score‬‬

‫‪229‬‬
‫‪student: Azhar , Score: 79‬‬

‫همانند یک لیست (‪ )List‬می تواندی با استفاده از متدهای ‪ Add‬و ‪ Remove‬آتم هایی به ‪ Hashtable‬اضافه و یا از آن کم کنید‪.‬مانند زیر ‪:‬‬

‫;)"‪students.Remove("Peter‬‬

‫همانطور که می بینید با استفاده از نام کلید‪ ،‬نه مقدار ‪ ،‬یک آیتم را می توان حذف نمود‪.‬‬

‫انواع ‪ Enumerator‬و ‪Enumerable‬‬

‫در درسهای قبلی دیدید که چگونه با استفاده از حلقه ‪ foreach‬عناصر یک آرایه را پیمایش میکردیم‪ .‬در این درس میخواهیم کمی دقیقتر به قضیه آرایهها‬
‫نگاه کنیم و ببینیم که چرا از آنها میتوانند توسط این حلقه مورد پردازش قرار گیرند‪ .‬همچنین یاد میگیرید که چطور از این قابلیت در کالسهایی که خودتان‬
‫تعریف کردهاید استفاده کنید‪.‬‬

‫استفاده از حلقه ‪foreach‬‬

‫وقتی که از حلقه ‪ foreach‬در یک آرایه استفاده میکنید‪ ،‬این حلقه تک تک اعضای آرایه را به شما ارائه داده و اجازه میدهد که مقادیر آنها را مشاهده کنید‪ .‬به‬
‫عنوان مثال در زیر یک آرایه با چهار عنصر تعریف شده است و میخواهیم با استفاده از حلقه ‪ foreach‬مقادیر عناصر آن را چاپ کنیم ‪:‬‬

‫;} ‪int[] number = { 10, 11, 12, 13‬‬


‫)‪foreach (int item in number‬‬
‫;)‪Console.WriteLine("Item value: {0}", item‬‬

‫‪Item value: 10‬‬


‫‪Item value: 11‬‬
‫‪Item value: 12‬‬
‫‪Item value: 13‬‬
‫اما چرا از این حلقه برای آرایهها استفاده میکنیم؟ چون آرایه به محض درخواست‪ ،‬یک شیء به نام ‪( enumerator‬شمارنده) تولید میکنند‪ .‬این شیء میتواند‬
‫عناصر آرایه را یک به یک و به ترتیب برگرداند‪ Enumerator .‬ترتیب عناصر آرایه را میداند و بعد از برگرداندن اولین عنصر موقعیت خود را حفظ کرده و در‬
‫درخواست بعدی عنصر بعدی آرایه را بر میگرداند‪ .‬برای انواعی که دارای شئ شمارنده (‪ )enumerator‬هستند یک راه برای به دست آوردن این شئ وجود‬
‫دارد و آن استفاده از متد ()‪ GetEnumerator‬است‪ .‬به انواعی که این متد را پیاده سازی میکنند نوع شمارش پذیر یا ‪ enumerable‬می گویند‪ .‬آرایه یک‬
‫نوع شمارش پذیر است‪.‬‬
‫از حلقه ‪ foreach‬برای کار با انواع شمارش پذیر (‪ )enumerable‬استفاده میشود‪ .‬وقتی که یک نوع شمارش پذیر به این حلقه میدهیم تا عناصر آن را‬
‫شمارش کند‪ ،‬مراحل زیر طی میشود ‪:‬‬

‫ابتدا شئ ‪ enumerator‬را با فراخوانی متد ()‪ GetEnumerator‬به دست میآورد‪.‬‬ ‫•‬


‫هر آیتم را از ‪ enumerator‬درخواست کرده و آن را برای شما قابل دسترس میکند (نه قابل تغییر)‪.‬‬ ‫•‬

‫رابط های ‪ IEnumerator‬و ‪IEnumerable‬‬


‫‪230‬‬
‫تمامی کالسهایی که به نحوی شامل یک ‪ Collection‬هستند‪ ،‬این دو رابط رو پیاده سازی میکنند‪ .‬وجود ‪ IEnumerable‬که توسط کالسها پیاده سازی‬
‫میشود به کالس این امکان را میدهد که بصورت ضمنی و توکار بشود شیء را پیمایش کرد‪ .‬دقیقاً به همین دلیل میتوان با استفاده از حلقه ‪ foreach‬یک‬
‫آرایه را پیمایش کرد‪ ،‬چون که رابط ‪ IEnumerable‬توسط کالس ‪ System.Array‬پیاده سازی میشود‪ .‬رابط ‪ IEnumerator‬در سطح پایینتری از‬
‫یک ‪ IEnumerable‬قرار دارد‪ .‬با استفاده از این رابط میتوان در هرجای بدنه متد اشیایی رو برگشت دهیم بدون اینکه مجبور باشیم ابتدا نتایج را مثالً در یک‬
‫آرایه بریزیم و بعد آن آرایه رو برگشت دهیم‪.‬‬

‫رابط ‪IEnumerator‬‬
‫یک شمارنده (‪ )enumerator‬رابط ‪ IEnumerator‬را پیاده سازی میکند که دارای دو متد () )(‪ Reset،MoveNext‬و یک خاصیت به نام ‪Current‬‬
‫میباشد‪ .‬خاصیت ‪ Current‬عنصر جاری یک مجموعه را بر میگرداند‪ .‬این خاصیت یک خاصیت فقط خواندنی (‪ )read-only‬است و چیزی که برمی گرداند‬
‫از نوع ‪ object‬میباشد‪ .‬متد ()‪ MoveNext‬متدی است که‪ ،‬مکان شمارنده را از یک آیتم در مجموعه به آیتمی دیگر منتقل میکند‪ .‬این متد یک مقدار بولی‬
‫را بر میگرداند که نشان میدهد که آیا مکان دیگری برای خواندن در دسترس است یا به انتهای مجموعه رسیده است‪ .‬اگر مکان جدیدی وجود داشته باشد مقدار‬
‫‪ true‬و در غیر اینصورت مقدار ‪ false‬را بر میگرداند‪ .‬مکان اولیه شمارنده قبل از اولین آیتم مجموعه است‪ ،‬بنابراین ()‪ MoveNext‬باید قبل از اولین‬
‫دسترسی خاصیت ‪ Current‬فراخوانی شود‪ .‬متد ()‪ Reset‬متدی برای برگرداندن شمارنده به موقعیت اولیه خود قبل از جابجایی است‪ .‬به تعبیری دیگر‪ ،‬موقعیت‬
‫اولیه مجموعه را برمی گرداند‪ .‬با در اختیار داشتن یک شمارنده (‪ )enumerator‬شما قادر خواهید بود که حلقه ‪ foreach‬را شبیه سازی کرده و عناصر یک‬
‫مجموعه را با استفاده ازمتد ()‪ MoveNext‬و خاصیت ‪ Current‬پیمایش کنید‪ .‬برای درک بهتر عملکرد دو متد و خاصیت مذکور به شکل و کد زیر توجه کنید‬
‫‪:‬‬

‫;} ‪int[] numbers = { 10, 11, 12, 13‬‬

‫;)(‪IEnumerator IEnumerator1 = numbers.GetEnumerator‬‬


‫;)(‪IEnumerator1.MoveNext‬‬
‫;‪int i = (int)IEnumerator1.Current‬‬

‫;))(‪Console.WriteLine(i.ToString‬‬

‫‪10‬‬
‫همانطور که در کد باال مشاهده میکنید متد ()‪ GetEnumerator‬آرایه ‪ numbers‬را به نوع شمارش پذیر تبدیل میکند‪ ،‬سپس با فراخوانی متد‬
‫()‪ MoveNext‬عدد ‪ 10‬که اولین عضو آرایه است به عنوان عنصر جاری (‪ )Current‬بر گردانده میشود‪ .‬حال فرض کنید که شما میخواهید عدد ‪ 12‬را‬
‫چاپ کنید‪ ،‬برای این کار باید متد ()‪ MoveNext‬را سه با فراخوانی کنید ‪:‬‬

‫;} ‪int[] numbers = { 10, 11, 12, 13‬‬

‫;)(‪IEnumerator IEnumerator1 = numbers.GetEnumerator‬‬

‫;)(‪IEnumerator1.MoveNext‬‬
‫;)(‪IEnumerator1.MoveNext‬‬
‫;)(‪IEnumerator1.MoveNext‬‬

‫;‪int i = (int)IEnumerator1.Current‬‬

‫‪231‬‬
Console.WriteLine(i.ToString());

12
‫ در‬.‫ به صورت خودکار انجام میدهد‬foreach ‫ بنابراین کد زیر روش دستی کاری است که حلقه‬،‫) هستند‬enumerable( ‫آرایهها از انواع قابل شمارش‬
:‫ تولید میکند‬foreach ‫ کدی شبیه به کد زیر را در هنگام نوشتن دستور‬C# ‫حقیقت کامپایلر‬

using System;
using System.Collections;

public class Program


{
public static void Main()
{
int[] numbers = { 10, 11, 12, 13 };

IEnumerator IEnumerator1 = numbers.GetEnumerator();

while (IEnumerator1.MoveNext())
{
int i = (int)IEnumerator1.Current;
Console.WriteLine("{0}", i);
}
}
}

10
11
12
13

IEnumerable ‫رابط‬
‫ فقط یک عضو دارد و آن‬IEnumerable ‫ رابط‬.‫ را پیاده سازی کند‬IEnumerable ‫) کالسی است که رابط‬enumerable( ‫یک کالس قابل شمارش‬
‫ این رابط در واقع کالس ما را قابل‬.‫ است‬IEnumberator ‫ میباشد و پارامتر برگشتی این متد از نوع همان رابط‬GetEnumerator)( ‫عضو هم متد‬
: ‫ فرم کلی بصورت زیر است‬.‫ را در مورد کالسمان بکار ببریم‬foreach ‫پیمایش میکند تا بتوانیم حلقه‬

using System.Collections;

class MyClass : IEnumerable


{
public IEnumerator GetEnumerator
{
...
}
...
}

‫ این‬.‫ را پیاده سازی میکند‬IEnumerator ‫ که رابط‬ColorEnumerator ‫ فرض کنید یک کالس به نام‬.‫اکنون یک مثال را با هم مرور میکنیم‬
: ‫ پس قابل پیمایش میشود‬،‫ را پیاده سازی میکند‬IEnumerator ‫ و چون رابط‬،‫کالس یک رشته از رنگها را در بر میگیرد‬

using System;
using System.Collections;
class ColorEnumerator : IEnumerator
{
string[] Colors;
int Position = -1;
public ColorEnumerator(string[] theColors) // Constructor

232
{
Colors = new string[theColors.Length];
for (int i = 0; i < theColors.Length; i++)
Colors[i] = theColors[i];
}

public object Current // Implement Current.


{
get
{
return Colors[Position];
}
}

public bool MoveNext() // Implement MoveNext.


{
if (Position < Colors.Length - 1)
{
Position++;
return true;
}
else
return false;
}

public void Reset() // Implement Reset.


{
Position = -1;
}
}

‫ پارامتری از نوع‬GetEnumerator)( ‫ این کالس در متد‬،‫ را پیاده سازی میکند‬IEnumerable ‫اکنون ما کالسی دیگر ایجاد میکنیم که رابط‬
: ‫کالس باال برمی گرداند مطابق شکل زیر‬

class MyColors : IEnumerable


{
string[] Colors = { "Red", "Yellow", "Blue" };
public IEnumerator GetEnumerator()
{
return new ColorEnumerator(Colors);
}
}

: ‫ به کد زیر توجه کنید‬.‫ برای پیمایش اعضای آن استفاده کنیم‬foreach ‫حال در برنامه براحتی میتوانیم از حلقه‬

class Program
{
static void Main()
{
MyColors MC = new MyColors();
foreach (string color in MC)
Console.WriteLine(color);
}
}

Red
Yellow
Blue

)Iterator( ‫پیمایشگر‬

233
‫‪ Iterator‬بلوک کدی است که‪ ،‬شامل همه مقادیری است که در یک حلقه ‪ foreach‬مورد استفاده قرار میگیرد‪ .‬یک کالس که نماینده یک کلکسیون‬
‫است میتواند رابط ‪ System.Collections.IEnumerable‬را پیاده سازی کند‪ .‬این رابط نیاز به پیاده سازی متد ()‪ GetEnumerator‬دارد که‬
‫یک رابط ‪ IEnumerator‬را بر میگرداند‪ .‬رابط ‪ IEnumerator‬دارای خاصیت ‪ Current‬میباشد که مقدار جاری برگشت داده شده بوسیله‬
‫‪ iterator‬را در بر دارد‪ .‬این رابط (‪ )IEnumerator‬همچنین دارای متد ()‪ MoveNext‬است که خاصیت ‪ Current‬را به سوی آیتم بعدی حرکت‬
‫می دهد و در صورت عدم وجود آیتم مقدار ‪ false‬را بر میگرداند‪ .‬متد ()‪ Reset‬حلقه پیمایش را به اولین آیتم بر میگرداند‪ .‬رابط ‪IEnumerator‬‬
‫توسط کلکسیونهای مختلف دات نت پیاده سازی میشود که یکی از این کلکسیونها آرایههای میباشند‪ .‬پس این سؤال پیش میآید که چگونه با استفاده‬
‫از حلقه ‪ foreach‬میتوان به اجزای این کلکسیونها دسترسی پیدا کرد؟ فرض کنید کدی شبیه به کد زیر داریم که همه عناصر یک آرایه را با استفاده از‬
‫حلقه ‪ foreach‬میخواند‪.‬‬

‫;} ‪int[] numbers = { 1, 2, 3, 4, 5‬‬

‫)‪foreach(int n in numbers‬‬
‫{‬
‫;)‪Console.WriteLine(n‬‬
‫}‬

‫برای درک بهتر کاربرد تکرارکنندهها (‪ ،)iterators‬اجازه دهید که حلقه ‪ foreach‬کد باال را به فراخوانی متد ()‪ GetEnumerator‬آرایه ترجمه کنیم ‪:‬‬

‫;} ‪int[] numbers = { 1, 2, 3, 4, 5‬‬

‫;)(‪IEnumerator iterator = numbers.GetEnumerator‬‬


‫))(‪while (iterator.MoveNext‬‬
‫{‬
‫;)‪Console.WriteLine(iterator.Current‬‬
‫}‬

‫همانطور که مشاهده میکنید ما ابتدا یک پیمایشگر آرایه را با استفاده از متد ()‪ GetEnumerator‬که یک رابط ‪ IEnumerator‬را بر میگرداند به‬
‫دست میآوریم‪ .‬سپس از این پیمایشگر در حلقه ‪ while‬استفاده کرده و متد ()‪ MoveNext‬را فراخوانی میکنیم‪ .‬متد ()‪ MoveNext‬اولین عنصر یک‬
‫کلکسیون مانند آرایه را بر میگرداند و اگر عملیات به دست آوردن اولین عنصر موفقیت آمیز باشد مقدار ‪ true‬را بر میگرداند‪ .‬در فراخوانی بعدی دومین‬
‫عنصر آرایه را بر میگرداند و این کار را تا آخرین عنصر آرایه انجام میدهد و وقتی که به پایان عناصر رسید مقدار ‪ false‬را برگشت میدهد‪ .‬مقدار برگشت‬
‫داده شده یک عنصر به وسیله خاصیت ‪ IEnumerator.Current‬قابل دسترسی است‪ .‬برای استفاده از ‪ iterator‬نیاز به دستور ‪yield return‬‬
‫داریم‪ .‬این دستور (‪ )yield‬با دستور ‪ return‬متفاوت است‪ .‬یکی از تفاوتهای مشهود این دو‪ ،‬استفاده از کلمه کلیدی ‪ yield‬قبل از کلمه کلیدی‬
‫‪ return‬میباشد‪ yield .‬یک عنصر مجموعه را برمی گرداند و موقعیت مکان نما را به عنصر بعدی هدایت میکند‪ .‬به کد زیر توجه کنید ‪:‬‬

‫‪public static IEnumerable‬‬ ‫)(‪GetMessages‬‬


‫{‬
‫‪yield return "Message‬‬ ‫;"‪1‬‬
‫‪yield return "Message‬‬ ‫;"‪2‬‬
‫‪yield return "Message‬‬ ‫;"‪3‬‬
‫}‬

‫)(‪public static void Main‬‬


‫{‬
‫))(‪foreach (string message in GetMessages‬‬
‫{‬
‫;)‪Console.WriteLine(message‬‬
‫}‬
‫}‬

‫‪234‬‬
Message 1
Message 2
Message 3
‫ مقدار جلوی‬.‫ میباشد‬GetEnumerator)( ‫ شامل تعریفی برای یک متد‬،‫ را بر میگرداند که‬IEnumerable ‫ یک شئ‬GetMessages)( ‫متد‬
‫ در حلقه‬GetMessages)( ‫ در فراخوانی بعدی متد‬.‫ قرار میگیرد و چاپ میشود‬foreach ‫ دستور‬message ‫ در متغیر‬yield return ‫اولین دستور‬
‫ برای توقف مقادیر برگشتی‬.‫ ادامه مییابد‬yield return ‫ چاپ میشود و این کار تا آخرین دستور‬yield return ‫ مقدار جلوی دومین دستور‬foreach
: ‫ به صورت زیر استفاده کرد‬yield break ‫از متد میتوان از دستور‬

public static IEnumerable GetMessages()


{
yield return "Message 1";
yield return "Message 2";
yield break;
yield return "Message 3";
}

‫ اجازه دهید با ذکر یک مثال نحوه استفاده از‬.‫ شما را با نحوه ایجاد یک پیمایشگر سفارشی آشنا میکنیم‬،‫حال که با نحوه عملکرد پیمایشگرها آشنا شدید‬
‫ میخواهیم یک پیمایشگر ایجاد کنیم که با استفاده از‬.‫ است توضیح دهیم‬ArrayList ‫پیمایشگر را به وسیله ایجاد یک کالس جدید که شامل یک فیلد‬
.‫ را به دست آورد‬ArrayList ‫ مقادیر‬foreach ‫حلقه‬

1: using System.Collections;
2: using System;
3:
4: public class Names : IEnumerable
5: {
6: private ArrayList innerList;
7:
8: public Names(params object[] names)
9: {
10: innerList = new ArrayList();
11:
12: foreach (object n in names)
13: {
14: innerList.Add(n);
15: }
16: }
17:
18: public IEnumerator GetEnumerator()
19: {
20: foreach (object n in innerList)
21: {
22: yield return n.ToString();
23: }
24: }
25: }
26:
27: public class Program
28: {
29: public static void Main()
30: {
31: Names nameList = new Names("John", "Mark", "Lawrence", "Michael", "Steven");
32:
33: foreach (string name in nameList)
34: {
35: Console.WriteLine(name);
36: }
37: }
38: }

John

235
‫‪Mark‬‬
‫‪Lawrence‬‬
‫‪Michael‬‬
‫‪Steven‬‬
‫ابتدا یک کالس مجموعهای به نام ‪ Names‬که شامل لیستی از نامها میباشد را ایجاد میکنیم (خطوط ‪ .)4-25‬همانطور که در تعریف کالس در خط ‪4‬‬
‫مشاهده میکنید‪ ،‬ما کالس ‪ CollectionBase‬را پیاده سازی نکردهایم‪ .‬چون که کالس ‪ CollectionBase‬رابط ‪ IEnumerable‬را پیاده سازی‬
‫میکند و در نتیجه دارای یک پیاده سازی از متد ()‪ GetEnumerator‬این رابط نیز است‪ .‬ما یک کالس مجموعهای را از صفر ایجاد و یک پیمایشگر‬
‫سفارشی را تعریف کردهایم‪ .‬از آنجاییکه کالس ما رابط ‪ IEnumerable‬را پیاده سازی کرده است پس الزم است که متد ()‪ GetEnumerator‬از این‬
‫رابط را هم پیاده سازی کند‪ .‬متد ()‪ GetEnumerator‬یک شمارنده است که کلکسیونها را شمارش میکند‪ .‬کلکسیون به مجموعهای از عناصر هم نوع‬
‫که الزاماً در حافظه پشت سر هم نیستند گفته میشود‪ .‬در خطوط ‪ 18-24‬پیمایشگر سفارشی را تعریف کردهایم‪ .‬در داخل آن به پیمایش هر یک از مقادیر‬
‫فیلد ‪ innerList‬میپردازیم‪ .‬هر مقدار به رشته تبدیل و و سپس با استفاده از دستور ‪ yield‬به متد فراخوان ارسال میشود‪.‬‬
‫خطوط ‪ 33 – 36‬پیمایشگر ما را در عمل نمایش میدهد‪ .‬از آنجاییکه دستور ‪ yield‬در پیمایشگرمان هر مقدار را به نوع رشته تبدیل میکند پس به راحتی‬
‫میتوانیم از نوع ‪ string‬در حلقه ‪ foreach‬استفاده کنیم (خط ‪ .)33‬وقتی که یک مقدار به وسیله پیمایشگر از طریق حلقه ‪ foreach‬واقع در متد‬
‫()‪ Main‬برگدانده میشود‪ ،‬حلقه ‪ foreach‬به آیتم بعدی رفته و دستور ‪ yield‬مقدار پیمایش شده از ‪ innerList‬را بر میگرداند‪ .‬بدون پیمایشگر ما‬
‫قادر به استفاده از حلقه ‪ foreach‬در کالسمان نیستیم‪ .‬ایجاد پیمایشگر سفارشی به ما این قدرت را میدهد که کنترل بیشتری بر رفتار حلقه ‪foreach‬‬
‫هنگام کار با کالس داشته باشیم‪ .‬به عنوان مثال میتوانیم پیمایشگر را به این صورت اصالح کنیم که فقط نامهایی که با حرف ‪ M‬شروع میشوند را‬
‫برگرداند ‪:‬‬

‫)(‪public IEnumerator GetEnumerator‬‬


‫{‬
‫)‪foreach (object n in innerList‬‬
‫{‬
‫))"‪if (n.ToString().StartsWith("M‬‬
‫;)(‪yield return n.ToString‬‬
‫}‬
‫}‬

‫همانطور که در کد باال مشاهده میکنید برای تشخیص اینکه چه نامی با حرف ‪ M‬شروع شده است از متد ()‪ StartsWith‬مربوط به کالس‬
‫‪ System.String‬استفاده کردهایم‪ .‬اگر نام با حرف ‪ M‬شروع شده باشد‪ ،‬دستور ‪ yield‬آن را بر میگرداند‪ ،‬در غیر اینصورت‪ ،‬از آن رد شده و به نام‬
‫بعدی در ‪ innerList‬را مورد بررسی قرار میدهد‪ .‬با دستکاری متد ()‪ ،GetEnumerator‬هنگام استفاده از حلقه ‪ foreach‬در یک نمونه از کالس‬
‫‪ ،Names‬میتوانیم فقط نامهایی را که با حرف ‪ M‬شروع میشوند را به دست آوریم‪ .‬اگر چه میتوانید از تکنیک باال استفاده کرده و متد‬
‫()‪ GetEnumerator‬تغییر دهید ولی بهتر است از یک متد جدا برای به دست آوردن نامهایی که با یک حرف خاص شروع میشوند استفاده کنید ‪:‬‬

‫)‪public IEnumerable GetNamesStartingWith(string letter‬‬


‫{‬
‫)‪foreach (object n in innerList‬‬
‫{‬
‫))‪if (n.ToString().StartsWith(letter‬‬
‫;)(‪yield return n.ToString‬‬
‫}‬
‫}‬

‫پیمایشگر باال نسبت به پیمایشگر قبلی منعطفتر بوده و شما میتوانید با استفاده از آن نامهایی که با یک حرف یا زیررشته خاص شروع شدهاند را پیدا کنید‪.‬‬
‫به این نکته توجه کنید که در پیمایشگر باال از ‪ IEnumerable‬به جای ‪ IEnumerator‬استفاده کردهایم‪ IEnumerable .‬دارای متد‬
‫()‪ GetEnumerator‬است‪ .‬هنگام فراخوانی این پیمایشگر الزم است که حلقه ‪ foreach‬خطوط ‪ 33-36‬را به صورت زیر تغییر دهید ‪:‬‬

‫))"‪foreach (string name in nameList.GetNamesStartingWith("M‬‬


‫{‬
‫‪236‬‬
‫;)‪Console.WriteLine(name‬‬
‫}‬

‫جنریک ها (‪)Generics‬‬

‫جنریک ها کالسها‪ ،‬متدها یا رابطهایی هستند که بسته به نوع دادهای که به آنها اختصاص داده میشود رفتارشان را سازگار میکنند‪ .‬به عنوان مثال میتوان‬
‫یک متد جنریک تعریف کرد که هر نوع دادهای را قبول کند‪ .‬همچنین میتوان یک متد ایجاد کرد که بسته به نوع دریافتی‪ ،‬مقادیری از انواع دادهای مانند ‪،int‬‬
‫‪ double‬یا ‪ string‬را نشان دهد‪ .‬اگر از جنریک ها استفاده نکنید باید چند متد و یا حتی چندین متد سربارگذاری شده برای نمایش هر نوع ممکن ایجاد کنید‪.‬‬

‫)‪public void Show(int number‬‬


‫{‬
‫;)‪Console.WriteLine(number‬‬
‫}‬

‫)‪public void Show(double number‬‬


‫{‬
‫;)‪Console.WriteLine(number‬‬
‫}‬

‫)‪public void Show(string message‬‬


‫{‬
‫;)‪Console.WriteLine(message‬‬
‫}‬

‫با استفاده از جنریک ها میتوان متد جنریکی ایجاد کرد که هر نوع دادهای را قبول کند‪.‬‬

‫)‪public void Show<E>(E item‬‬


‫{‬
‫;)‪Console.WriteLine(item‬‬
‫}‬

‫متدهای جنریک را در درسهای آینده توضیح خواهیم داد‪ .‬حتماً این سؤال را از خودتان میپرسید که چرا نباید از نوع آبجکت که هر نوع دادهای را قبول میکند‬
‫استفاده کنیم؟ در آینده مشاهده میکنید که با استفاده از جنریک ها نیاز به عمل ‪( cast‬تبدیل صریح) ندارید‪ .‬درباره جنریک ها در درسهای بعد مطالب بیشتری‬
‫توضیح میدهیم‪.‬‬

‫متدهای جنریک‬

‫اگر بخواهید چندین متد با عملکرد مشابه ایجاد کنید و فقط تفاوت آنها در نوع دادهای باشد که قبول میکنند (مثالً یکی نوع ‪ int‬و دیگری نوع ‪ double‬را‬
‫قبول کند) می توان از متدهای جنریک برای صرفه جویی در کدنویسی استفاده کرد‪ .‬ساختار عمومی یک متد جنریک به شکل زیر است ‪:‬‬

‫)‪returnType methodName<type> (type argument1‬‬


‫{‬

‫‪237‬‬
‫;‪type someVariable‬‬
‫}‬

‫مشاهده می کنید که بعد از نام متد یک نوع در داخل دو عالمت بزرگتر و کوچکتر آمده است ( >‪ ) <type‬که همه انواع در سی شارپ میتوانند جایگزین آن‬
‫شوند‪ .‬برنامه زیر مثالی از نحوه استفاده از متد جنریک میباشد ‪:‬‬

‫;‪using System‬‬

‫‪public class Program‬‬


‫{‬
‫)‪public static void Show<X>(X val‬‬
‫{‬
‫;)‪Console.WriteLine(val‬‬
‫}‬

‫)(‪public static void Main‬‬


‫{‬
‫;‪int intValue = 5‬‬
‫;‪double doubleValue = 10.54‬‬
‫;"‪string stringValue = "Hello‬‬
‫;‪bool boolValue = true‬‬

‫;)‪Show(intValue‬‬
‫;)‪Show(doubleValue‬‬
‫;)‪Show(stringValue‬‬
‫;)‪Show(boolValue‬‬
‫}‬
‫}‬

‫‪5‬‬
‫‪10.54‬‬
‫‪Hello‬‬
‫‪true‬‬
‫یک متد جنریک ایجاد کردهایم که هر نوع دادهای راقبول کرده و مقادیر آنها را نمایش میدهد (خطوط ‪ .)5-8‬سپس دادههای مختلفی با وظایف یکسان به آن‬
‫ارسال میکنیم‪ .‬متد نیز نوع ‪ X‬را بسته به نوع دادهای که به عنوان آرگومان ارسال شده است تغییر میدهد‪ .‬به عنوان مثال وقتی یک داده از نوع ‪ int‬ارسال‬
‫میکنیم‪ ،‬همه مکانهایی که ‪ X‬در آنها وجود دارد به ‪ int‬تبدیل میشوند و متد به صورت زیر در میآید ‪:‬‬

‫)‪public static void Show (int val‬‬


‫{‬
‫;)‪Console.WriteLine(val‬‬
‫}‬

‫همچنین هنگام فراخوانی متد جنریک صریحاً میتوانید نوعی را که به وسیله آن مورد استفاده قرار میگیرد ذکر کنید (البته الزم نیست)‪ .‬به عنوان مثال‬
‫فراخوانیهای متد باال را میتوان به صورت زیر هم نوشت ‪:‬‬

‫;)‪Show<int>(intValue‬‬
‫;)‪Show<double>(doubleValue‬‬
‫;)‪Show<string>(stringValue‬‬

‫‪238‬‬
‫;)‪Show<bool>(boolValue‬‬

‫به یک نکته در مورد استفاده از متدهای جنریک توجه کنید و آن این است که‪ ،‬قبل از دانت نت ‪ ،4.5‬انجام محاسبات به وسیله متدهای جنریک امکان پذیر نبود‪.‬‬
‫یعنی شما نمی توانستید که دو عدد را با هم جمع کنید‪:‬‬

‫)‪public static void Show<X>(X val1, X val2‬‬


‫{‬
‫;)‪Console.WriteLine(val1 + val2‬‬
‫}‬

‫ولی در نسخه ‪ 4.5‬دات نت این مشکل با استفاده از کلمه کلیدی ‪ dynamic‬به صورت زیر قابل حل است ‪:‬‬

‫;)‪Console.WriteLine((dynamic)val1 + (dynamic)val2‬‬

‫شما می توانید چندین نوع خاص را برای متد جنریک ارسال کنید‪ ،‬برای این کار هر نوع را به وسیله کاما از دیگری جدا کنید‪.‬‬

‫)‪public static void Show<X, Y>(X val1, Y val2‬‬


‫{‬
‫;)‪Console.WriteLine(val1‬‬
‫;)‪Console.WriteLine(val2‬‬
‫}‬

‫به مثال زیر که در آن دو مقدار مختلف به متد ارسال شده است توجه کنید ‪:‬‬

‫;)‪Show(5, true‬‬

‫‪// OR‬‬

‫;)‪Show<int, bool>(5, true‬‬

‫مشاهده میکنید که ‪ X‬با نوع ‪ int‬و ‪ Y‬با نوع ‪ bool‬جایگزین میشود‪ .‬این نکته را نیز یادآور شویم که شما میتوانید دو آرگومان هم نوع را هم به متد ارسال‬
‫کنید ‪:‬‬

‫;)‪Show(5, 10‬‬

‫‪// OR‬‬

‫;)‪Show<int, int>(5, true‬‬

‫کالس جنریک‬

‫تعریف یک کالس جنریک بسیار شبیه به تعریف یک متد جنریک است‪ .‬کالس جنریک دارای یک عالمت بزرگتر و کوچکتر و یک نوع پارامتر خاص میباشد‪.‬‬
‫برنامه زیر مثالی از یک کالس جنریک میباشد ‪:‬‬

‫;‪using System‬‬

‫‪239‬‬
public class GenericClass<T>
{
private T someField;

public GenericClass(T someVariable)


{
someField = someVariable;
}

public T SomeProperty
{
get { return someField; }
set { someField = value; }
}
}

public class Program


{
public static void Main()
{
GenericClass<double> genericDouble = new GenericClass<double>(30.50);
GenericClass<int> genericInt = new GenericClass<int>(10);

Console.WriteLine("genericDouble.SomeProperty = {0}",
genericDouble.SomeProperty);
Console.WriteLine("genericInt.SomeProperty = {0}",
genericInt.SomeProperty);

genericDouble.SomeProperty = 100.32;
genericInt.SompProperty = 50;
}
}

genericDouble.SomeProperty = 30.50
genericInt.SomeProperty = 10
‫ در آنها قرار دارد بعداً توسط‬T ‫ تمام مکانهایی که ورودی‬.‫ یک خاصیت و یک سازنده است را ایجاد میکنیم‬،‫در مثال باال یک کالس جبریک که دارای یک فیلد‬
‫ مانند‬.)<int>( ‫ یک نوع هم برای آن در نظر بگیرید‬،‫ وقتی یک نمونه از کالس جنریک تان ایجاد میکنید‬.‫ جایگزین میشوند‬،‫انواعی که مد نظر شما است‬
.‫متدهای جنریک میتوانید چندین نوع پارامتر به کالسهای جنریک اختصاص دهید‬

public class GenericClass<T1, T2, T3>


{
private T1 someField1;
private T2 someField2;
private T3 someField3;
}

.‫ از آنها نمونه جدید ایجاد کنید‬،‫ نمیتوانید مانند مثال زیر‬،‫ از چه نوعی هستند‬T3 ‫ و‬T2 ،T1 ‫چون نمیدانید‬

public GenericClass //Constructor

240
‫{‬
‫;)(‪someField1 = new T1‬‬
‫;)(‪someField2 = new T2‬‬
‫;)(‪someField3 = new T3‬‬
‫}‬

‫کالسهای غیر جنریک میتوانند از کال سهای جنریک ارث بری کنند‪ ،‬اما باید یک نوع برای پارامترکالس پایه جنریک تعریف کنید‪.‬‬

‫>‪public class MyClass : GenericClass<int‬‬


‫{‬

‫}‬

‫یک کالس جنریک هم میتواند از یک کالس غیر جنریک ارث بری کند‪.‬‬

‫محدودیت نوع (‪)Type Constraints‬‬

‫کد جنریک باید برای هر نوع دادهای کار کند‪ .‬یک عمل محاسباتی مانند عمل جمع که بر روی انواع صحیح انجام میشود‪ ،‬نمیتواند در صورتی که عملگر ‪+‬‬
‫سربارگذاری نشده باشد‪ ،‬بر روی سایر اشیاء عمل کند‪ .‬در نتیجه شما باید برای یک متد یا کالس جنریک محدودیت نوع (‪ )Type Constraints‬در نظر‬
‫بگیرید که فقط انواع خاصی در این لیست محدودیت قرار بگیرند‪.‬‬

‫‪public class GenericClass<T> where T: int‬‬


‫{‬
‫‪//some code‬‬
‫}‬

‫برای ایجاد این محدودیت ابتدا کلمه کلیدی ‪ where‬سپس نام نوع پارامتر‪ ،‬یک کالن (‪ ):‬و در آخر اگر پارامتر ‪ T‬دارای لیستی از محدودیتها است باید آنها را به‬
‫وسیله کاما از هم جدا کنیم‪ .‬کد باال دارای یک محدودیت است و آن نوع ‪ int‬میباشد‪ ،‬بدین معنی که کالس جنریک ما فقط میتواند این نوع را قبول کند‪ .‬اگر‬
‫بخواهید چندین محدودیت ایجاد کنید باید به صورت زیر عمل نمایید ‪:‬‬

‫‪public class GenericClass<T> where T: int, string‬‬


‫{‬
‫‪//some code‬‬
‫}‬

‫پارامتر ‪ T‬در کد باال فقط نوع ‪ int‬و ‪ string‬را قبول میکند‪ .‬میتوانید از کلمه کلیدی ‪ struct‬استفاده کنید بدین معنی که‪ ،‬کالس جنریک فقط انواع مقداری‬
‫را قبول کند و یا کلمه کلیدی ‪ Class‬را به کار برید که کالس جنریک فقط انواع مرجع را پذیرا باشد‪ .‬همچنین میتوان از کلمه کلیدی ‪ interface‬هم استفاده‬
‫کرد‪ ،‬که در نتیجه کالس میتواند اشیایی که رابطها را پیاده سازی میکنند را‪ ،‬قبول کند‪.‬‬

‫‪public class GenericClass<T> where T: struct‬‬


‫{‬
‫‪//some code‬‬
‫}‬
‫‪241‬‬
‫‪public class GenericClass<T> where T: class‬‬
‫{‬
‫‪//some code‬‬
‫}‬

‫‪public class GenericClass<T> where T: interface‬‬


‫{‬
‫‪//some code‬‬
‫}‬

‫همچنین می توان نام یک کالس را به عنوان محدودیت نوع تعیین کرد‪ .‬بدین معنی که نوع را محدود به آن کالس و کالسهای مشتق شده از آن کند‪ .‬میتوان‬
‫تعیین کرد که کالس جنریک فقط کالسهایی که دارای یک سازنده بدون پارامتر هستند را قبول کند‪ .‬برای ایجاد این محدودیت باید از ()‪ new‬به صورت زیر‬
‫استفاده شود ‪:‬‬

‫)(‪public class GenericClass<T> where T: new‬‬


‫{‬
‫‪//some code‬‬
‫}‬

‫در این مورد اگر چندین محدودیت وجود داشته باشد باید ()‪ new‬را در آخر آنها قرار دهیم‪ .‬اگر کالس دارای چندین پارامتر باشد و شما بخواهید برای هر یک از‬
‫آنها محدودیتهای مختلفی ایجاد کند میتوانید دستور ‪ where‬را به صورت زیر اعمال نمایید ‪:‬‬

‫‪public class GenericClass<T1, T2> where T1 : int where T2 : string‬‬


‫{‬
‫‪//some code‬‬
‫}‬

‫اگر یک کالس جنریک از یک کالس دیگر ارث بری کند باید نام آن کالس را قبل از محدودیتها ذکر نمایید‪.‬‬

‫‪public class GenericClass<T1, T2> : BaseClass where T1 : int where T2 : string‬‬


‫{‬
‫‪//some code‬‬
‫}‬

‫کلکسیون عمومی (‪)Generic Collection‬‬

‫میتوان یک کلکسیون عمومی تعریف کرد که شامل هر نوع دادهای باشد‪ .‬برای ایجاد یک کلکسیون عمومی از کالس >‪ List<T‬مربوط به فضای نامی‬
‫‪ System.Collections.Generics‬استفاده میشود‪ List<T> .‬میتواند مجموعهای از اشیاء نوع ‪ T‬باشد‪ .‬در نتیجه >‪ List<int‬مجموعهای از مقادیر‬
‫صحیح است‪.‬‬
‫کالس >‪ List<T‬دارای متدهای )(‪ RemoveAt() ،Remove() ،AddRange‬و دیگر متدهایی است که در کالس کلکسیونمان در درس قبلی از آنها‬
‫استفاده کردیم‪.‬‬

‫‪242‬‬
using System;
using System.Collections.Generic;

public class Animal


{
public string Type;

public Animal(string type)


{
Type = type;
}
}
public class Program
{
public static void Main()
{
List<Animal> animals = new List<Animal>();

animals.Add(new Animal("Dog"));
animals.Add(new Animal("Cat"));
animals.Add(new Animal("Rat"));

foreach (Animal animal in animals)


{
Console.WriteLine(animal.Type);
}
}
}

Dog
Cat
Rat
‫ میتوانید‬.‫ که در درس بعد در مورد آن توضیح داده میشود‬،‫ است‬collection initializers ‫یکی دیگر از روشهای مقداردهی به یک کلکسیون استفاده از‬
.‫ نوع مقدار را مشخص میکند‬Tval ‫ نوع کلید و‬Tkey .‫ که در فضای نامی ذکر شده قرار دارد استفاده کنید‬Dictionary<TKey, TVal> ‫از کالس‬

using System;
using System.Collections.Generic;

public class Animal


{
public string Type;

public Animal(string type)


{
Type = type;
}
}
public class Program
{
public static void Main()
{

243
‫;)(>‪Dictionary<string, Animal> animals = new Dictionary<string, Animal‬‬

‫;))"‪animals.Add("Animal1", new Animal("Dog‬‬


‫;))"‪animals.Add("Animal2", new Animal("Cat‬‬
‫;))"‪animals.Add("Animal3", new Animal("Rat‬‬

‫)‪foreach (Animal animal in animals.Values‬‬


‫{‬
‫;)‪Console.WriteLine(animal.Type‬‬
‫}‬
‫}‬
‫}‬

‫یک دیکشنری تعریف کردهایم که دارای کلیدهایی از نوع ‪ string‬و مقادیری از نوع کالس ‪ Animal‬میباشد‪ .‬برای به دست آوردن مقدار آیتمهای دیکشنری‬
‫کرد‪.‬‬ ‫استفاده‬ ‫است‬ ‫دیکشنری‬ ‫آیتمهای‬ ‫همه‬ ‫شامل‬ ‫که‬ ‫‪Values‬‬ ‫خاصیت‬ ‫از‬ ‫میتوان‬
‫خاصیت ‪ Keys‬نیز برای به دست آوردن همه کلیدهای یک دیکشنری به کار میرود‪ .‬کالسهایی را که معرفی کردیم بسیار شبیه به کالسهای ‪collection‬‬
‫و ‪ dictionary‬هستند که از کالسهای ‪ CollectionBase‬و ‪ DictionaryBase‬ارث بری میکنند‪ .‬اما نیازی به ساخت کالسهای کالکشن باال‬
‫نیست‪ .‬فقط کافی است که نوع آیتم مورد نظر را به کالسهای >‪ List<T‬و >‪ Dictionary<TKey,Tvalue‬ارسال نمایید‪ .‬برای اینکه از قابلیتهای‬
‫بیشتری بهره مند شوید میتوانید از ‪ collection‬و ‪ dictionary‬سفارشی استفاده نمایید (یعنی کالسهایی که از ‪ CollectionBase‬و‬
‫‪ DictionaryBase‬ارث بری میکنند و شما خود متدهای )(‪ Add‬و )(‪ Remove‬آنها را پیاده سازی میکنید)‪.‬‬

‫‪Object Initializer‬‬
‫‪ Object Initializer‬به شما اجازه میدهد‪ ،‬خاصیت ها را در داخل کالس مقداردهی کنید‪ .‬اگر به عنوان مثال چندین خاصیت داشته باشید و نخواهید که یک‬
‫سازنده را جهت مقداردهی به آنها تعریف کنید‪ ،‬میتوانید از ‪ object initializer‬استفاده نمایید‪ .‬به عنوان مثال به کد زیر توجه کنید ‪:‬‬

‫;‪using System‬‬

‫‪public class Sample‬‬


‫{‬
‫‪public int‬‬ ‫} ;‪Property1 { get; set‬‬
‫} ;‪public string Property2 { get; set‬‬
‫‪public bool‬‬ ‫} ;‪Property3 { get; set‬‬
‫}‬

‫‪public class Program‬‬


‫{‬
‫)(‪public static void Main‬‬
‫{‬
‫;)(‪Sample sampleClass = new Sample‬‬
‫;‪sampleClass.Property1 = 100‬‬
‫;"‪sampleClass.Property2 = "Sample‬‬
‫;‪sampleClass.Property3 = true‬‬
‫}‬

‫‪244‬‬
‫}‬

‫همانطور که مشاهده میکنید‪ ،‬الزم است که مقادیر را تک به تک به خاصیتها اختصاص دهیم‪ .‬با استفاده از ‪ object initializers‬میتوان کد را سادهتر کرد‬
‫‪:‬‬

‫‪public class Program‬‬


‫{‬
‫)(‪public static void Main‬‬
‫{‬
‫‪Sample sampleClass = new Sample‬‬
‫{‬
‫‪Property1 = 100,‬‬
‫‪Property2 = "Hello",‬‬
‫‪Property3 = true‬‬
‫;}‬
‫}‬
‫}‬

‫مشاهده میکنید که‪ ،‬بعد از ایجاد یک شیء از کالس به جای پرانتز از آکوالد استفاده کرده و سپس با لیست کردن خاصیتها مقادیری را که الزم داریم‪ ،‬به آنها‬
‫اختصاص میدهیم‪ .‬به این نکته نیز توجه کنید که خواص به وسیله کاما از هم جدا میشوند‪ .‬هنگام استفاده از ‪ object initializers‬سازنده پیشفرض بدون‬
‫پارامتر قبل از هر خاصیت مقداردهی شده فراخوانی میشود‪ .‬از آنجاییکه سازنده پیشفرض قبل از اختصاص مقادیر به خاصیتها اجرا میشود‪ ،‬میتوانید مقادیری‬
‫پیشفرضی به هر یک از خواص اختصاص بدهید‪ ،‬با این کار الزم نیست که حتماً به همه خواص با استفاده از ‪ initializer‬مقدار اختصاص داده شود‪ .‬اگر یه‬
‫سازنده غیر پیشفرض (‪ ) non-default constructor‬به کالس اضافه کنید باز هم باید یک سازنده بدون پارامتر پیشفرض برای قدرت استفاده از ‪object‬‬
‫‪ initializers‬وجود داشته باشد‪ .‬میتوان از ‪ object initializers‬تو در تو نیز استفاده نمود‪ .‬فرض کنید کالس ‪ Sample‬مان یک خاصیت از نوع‬
‫‪ Animal‬که دارای دو خاصیت ‪ Name‬و ‪ Age‬هست را دارا میباشد‪.‬‬

‫‪Sample sampleClass = new Sample‬‬


‫{‬
‫‪Property1 = 100,‬‬
‫‪Property2 = "Hello",‬‬
‫‪Property3 = true,‬‬
‫;} ‪Property4 = new Animal { Name = "Kitty", Age = 3‬‬
‫;}‬

‫نوع دیگر از مقداردهنده ها ‪ collection initializers‬میباشند‪ collection initializers .‬بسیار شبیه به ‪ array initializers‬میباشند با این‬
‫تفاوت که در کلکسیونهای عمومی (‪ )generic‬استفاده میشوند‪.‬‬

‫;‪1: using System‬‬


‫;‪2: using System.Collections.Generic‬‬
‫‪3:‬‬
‫‪4: namespace ObjectInitializer‬‬
‫{ ‪5:‬‬
‫‪6:‬‬ ‫‪class Person‬‬
‫‪7:‬‬ ‫{‬
‫‪8:‬‬ ‫} ;‪public string FirstName { get; set‬‬
‫‪9:‬‬

‫‪245‬‬
‫‪10:‬‬ ‫)‪public Person(string f‬‬
‫‪11:‬‬ ‫{‬
‫‪12:‬‬ ‫;‪FirstName = f‬‬
‫‪13:‬‬ ‫}‬
‫‪14:‬‬ ‫}‬
‫‪15:‬‬
‫‪16:‬‬ ‫‪class Program‬‬
‫‪17:‬‬ ‫{‬
‫‪18:‬‬ ‫)‪static void Main(string[] args‬‬
‫‪19:‬‬ ‫{‬
‫‪20:‬‬ ‫>‪List<Person> people = new List<Person‬‬
‫‪21:‬‬ ‫{‬
‫‪22:‬‬ ‫‪new Person("John"),‬‬
‫‪23:‬‬ ‫‪new Person("Jenny"),‬‬
‫‪24:‬‬ ‫)"‪new Person("Joe‬‬
‫‪25:‬‬ ‫;}‬
‫‪26:‬‬
‫‪27:‬‬ ‫)‪foreach (var person in people‬‬
‫‪28:‬‬ ‫{‬
‫‪29:‬‬ ‫;))‪Console.WriteLine(String.Format("{0}", person.FirstName‬‬
‫‪30:‬‬ ‫}‬
‫‪31:‬‬ ‫}‬
‫‪32:‬‬ ‫}‬
‫} ‪33:‬‬

‫‪John‬‬
‫‪Jenny‬‬
‫‪Joe‬‬
‫کد زیر نشان میدهد که بدون استفاده از ‪ ،collecition initializers‬الزم بود که در خطوط ‪ 20-25‬آیتمها را به صورت دستی و با استفاده از متد ()‪Add‬‬
‫اضافه کرده یا یک سازنده ایجاد کنیم‪ ،‬که آیتمهایی برای کلکسیون قبول کند‪.‬‬

‫;)(>‪List<Person> people = new List<Person‬‬

‫;))"‪people.Add(new Person("John‬‬
‫;))"‪people.Add(new Person("Jenny‬‬
‫;))"‪people.Add(new Person("Joe‬‬

‫انواع تهی‬

‫میتوانید انواع سادهای مانند ‪ int‬و ‪ double‬ایجاد کنید که مقادیر آنها تهی (‪ )null‬باشد‪ .‬مقادیر تهی فقط قابلیت ذخیره سازی انواع مرجع مانند رشتهها و سایر‬
‫اشیاء را دارند‪ .‬سی شارپ به شما اجازه میدهد انواع مقداری را تغییر دهید به طوریکه بتوانند به عنوان انواع تهی به کار روند‪ .‬میتوانید از‬
‫>‪ System.Nullable<T‬استفاده کنید که در آن ‪ T‬نوعی است که به انواع تهی تبدیل میشود‪.‬‬

‫;‪Nullable<int> nullInt = null‬‬


‫;‪Nullable<double> nullDouble = null‬‬

‫همچنین میتوانید به نوع عالمت? را نیز اضافه کنید‪.‬‬


‫‪246‬‬
‫;‪int? nullInt = null‬‬
‫;‪double? nullDouble = null‬‬

‫با استفاده از کد زیر میتوانید تست کنید که آیا متغیر دارای مقدار تهی میباشد یا نه؟‬

‫)‪if (nullInt == null‬‬


‫{‬
‫}‬

‫)‪if (nullDouble.HasValue‬‬
‫{‬
‫}‬

‫از آنجاییکه ما آنها را به انواع تهی تبدیل کردهایم نمیتوان آنها را در یک متغیر از انواع غیر تهی ذخیره نمود‪ .‬مثالً کد زیر مجاز نیست ‪:‬‬

‫;‪int? nullInt = null‬‬


‫;‪int myNumber = nullInt‬‬

‫برای این کار الزم است که ابتدا آنها را به حالت اصلی برگردانید ‪:‬‬

‫;‪int myNumber = (int)nullInt‬‬

‫اگر بخواهید یک نوع تهی با یک مقدار تهی را به حالت اولیه تبدیل کنید یک استثناء روی میدهد‪ .‬وقتی دو نوع تهی (به استثنای نوع بولی ؟) را در یک عملیات‬
‫در گیر می کنیم‪ ،‬اگر یکی از عملوندها تهی باشد نتیجه تهی خواهد بود‪ .‬نتایج ممکن برای نوع بولی ؟ در جدول زیر آمده است ‪:‬‬
‫‪var1 | var2 var1 & var2 var2 var1‬‬

‫‪true‬‬ ‫‪null null true‬‬

‫‪null‬‬ ‫‪false null false‬‬

‫‪true‬‬ ‫‪null true null‬‬

‫‪null‬‬ ‫‪false false null‬‬

‫‪null‬‬ ‫‪null null null‬‬

‫اگر شما بخواهید از ‪ null‬شدن نتیجه یک عبارت در صورتی که یکی از عملوندهای آن عبارت ‪ null‬باشد جلوگیری کنید‪ ،‬باید از عملگر ؟؟ استفاده کنید‪.‬‬

‫;‪int? nullInt = null‬‬


‫;‪int number = nullInt * 5 ?? 10‬‬

‫خط دوم نحوهی استفاده از این عملگر را توضیح میدهد‪ .‬برای نوشتن عبارتی معادل کد باال از یک عملگر ‪ 3‬تایی به صورت زیر استفاده میکنیم‪.‬‬

‫;‪int number = (nullInt * 5) == null ? (nullInt * 5) : 10‬‬

‫اگر نتیجه عبارت در سمت چپ عملگر ؟؟ برابر ‪ null‬باشد نتیجه عبارت سمت راست عملگر و در غیر این صورت نتیجه مقدار سمت چپ عملگر در متغیر‬
‫‪ number‬ذخیره میشود‬
‫‪247‬‬
‫عملگر (??) ‪null Coalescing‬‬

‫عملگر ‪ ،null coalescing‬یک عملگر باینری است که‪ ،‬برای تشخیص مقدار دو عملوند به کار میرود‪ .‬کاربرد اصلی این عملگر در قرار دادن یک مقدار‬
‫‪ nullable‬در یک مقدار ‪ non-nullable‬با استفاده از یک دستورالعمل ساده است‪ .‬در زیر نحوه استفاده از عملگر ‪ null coalescing‬نشان داده شده است‬
‫‪:‬‬

‫;‪var result = operand1 ?? operand2‬‬

‫‪ operand1‬و ‪ operand2‬میتوانند متغیر‪ ،‬فراخوانی یک متد و یا یک عبارت باشند‪ .‬اگر ‪ operand1‬یک متغیر با مقدار تهی باشد و یا فراخوانی یک متد و‬
‫یا عبارتی باشد که یک مقدار تهی را تولید کند در این صورت عملگر ‪ null coalescing‬به سراغ مقدار عملوند ‪ operand2‬میرود‪ .‬اگر مقدار این عملوند‬
‫غیر تهی باشد عملگر ‪ null coalescing‬از آن در نتیجه محاسبه استفاده میکند‪ .‬به مثال زیر توجه کنید ‪:‬‬

‫‪1: public class Program‬‬


‫{ ‪2:‬‬
‫‪3:‬‬ ‫)‪public static void Main(string[] args‬‬
‫‪4:‬‬ ‫{‬
‫‪5:‬‬ ‫;‪int? num1 = null‬‬
‫‪6:‬‬ ‫;‪int? num2 = 100‬‬
‫‪7:‬‬
‫‪8:‬‬ ‫;‪int? num3 = num1 ?? num2‬‬
‫‪9:‬‬
‫‪10:‬‬ ‫;)"}‪Console.WriteLine($"Value is {num3‬‬
‫‪11:‬‬ ‫}‬
‫} ‪12:‬‬

‫‪Value is 100‬‬

‫در خط ‪ 8‬مثال باال از عملگر ‪ null coalescing‬استفاده کردهایم‪ .‬از آنجاییکه مقدار اولیه ‪ num1‬برابر ‪ null‬و مقدار ‪ num2‬یک مقدار غیر تهی است‪ ،‬در‬
‫میگیرد‪.‬‬ ‫قرار‬ ‫‪num3‬‬ ‫متغیر‬ ‫در‬ ‫‪num2‬‬ ‫مقدار‬ ‫نتیجه‬
‫در مثال زیر هم یک متد را فراخوانی میکنیم‪ .‬البته به طور قطع نمیدانیم که آیا با فراخوانی آن یک مقدار تهی برگشت داده میشود و یا یک مقدار غیر تهی ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: namespace NullCoalescingOperator‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫‪public class Program‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫)‪public static void Main(string[] args‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫;)(‪Random randomizer = new Random‬‬

‫‪248‬‬
‫‪10:‬‬
‫‪11:‬‬ ‫;)‪int? result = GetNullOrIntValue(randomizer.Next(1, 10)) ?? default(int‬‬
‫‪12:‬‬
‫‪13:‬‬ ‫;)"}‪Console.WriteLine($"Result is {result‬‬
‫‪14:‬‬ ‫}‬
‫‪15:‬‬
‫‪16:‬‬ ‫)‪public static int? GetNullOrIntValue(int randomValue‬‬
‫‪17:‬‬ ‫{‬
‫‪18:‬‬ ‫)‪if (randomValue % 2 == 0‬‬
‫‪19:‬‬ ‫{‬
‫‪20:‬‬ ‫;‪return null‬‬
‫‪21:‬‬ ‫}‬
‫‪22:‬‬
‫‪23:‬‬ ‫;‪return 100‬‬
‫‪24:‬‬ ‫}‬
‫‪25:‬‬ ‫}‬
‫} ‪26:‬‬

‫‪Result is 100‬‬
‫‪Result is 0‬‬
‫در مثال باال یک متد به نام ()‪ GetNullOrIntValue‬تعریف کردهایم که یک مقدار تصادفی به عنوان آرگومان قبول میکند‪ .‬این متد در صورتی که یک‬
‫مقدار زوج به آن ارسال شود مقدار ‪ null‬و در غیر اینصورت مقدار ‪ 100‬را بر میگرداند‪ .‬وقتی که در خط ‪ 11‬این متد را فراخوانی میکنیم‪ ،‬یک مقدار تصافی به‬
‫عنوان آرگومان به آن ارسال میشود‪ .‬عملوند دومی که برای عملگر ‪ null coalescing‬استفاده میکنیم کلمه کلیدی ‪ default‬است که برای تشخیص مقدار‬
‫پیشفرض نوع ‪ int‬یعنی عدد صفر به کار برده شده است‪ .‬اگر با فراخوانی متد به طور تصادفی یک مقدار زوج به آن ارسال شود‪ ،‬متد مقدار پیشفرض نوع ‪ int‬و در‬
‫غیر اینصورت یک مقدار غیر تهی (یعنی ‪ )100‬را بر میگرداند‪.‬‬

‫رویداد ها (‪)Events‬‬

‫رویدادها‪ ،‬رفتارها یا اتفاقاتی هستند که‪ ،‬در هنگام اجرای برنامه روی میدهند‪ .‬رویدادها معموالً در برنامههای ویژوال مانند ویندوزها یا صفحات وب استفاده‬
‫می شوند‪ .‬برخی از رویدادها عبارتند از کلیک کردن بر روی ماوس‪ ،‬تایپ یک متن در ‪ ،TextBox‬تغییر انتخاب یک آیتم در یک لیست و غیره… ‪ .‬در برنامههای‬
‫کنسول‪ ،‬میتوانیم به صورت دستی یک رویداد را راه اندازی کنیم‪ .‬بدین صورت که‪ ،‬یک بلوک کد اضافه میکنیم که‪ ،‬وقتی یک حالت خاص اتفاق افتاد‪ ،‬اجرا‬
‫شود‪ .‬چندین کنترل کننده رویداد‪ ،‬میتوانند به یک رویداد متصل شوند‪ .‬یک کنترل کننده رویداد‪ ،‬متدی است که امضای آن شبیه به امضای ‪ delegate‬مربوط‬
‫به رویداد است‪ .‬زیرا هر رویداد به طور ضمنی شامل یک ‪ delegate‬در داخل خود است‪ .‬زمانی که شما یک کنترل کننده رویداد را به یک رویداد متصل‬
‫میکنید‪ ،‬در واقع شما کنترل کننده یا همان متد را در داخل ‪ delegate‬رویداد قرار میدهید‪ .‬در نتیجه وقتی یک رویداد آزاد میشود‪ ،‬همه کنترل کنندههای‬
‫رویداد متصل به آن‪ ،‬اجرا میشوند‪ .‬به طور کلی میتوان گفت که ‪:‬‬
‫هر رویداد دارای یک ‪ delegate‬داخلی مربوط به خود است و در نتیجه وقتی که رویداد به وقوع میپیوندد‪ ،‬متدهای داخل ‪ delegate‬اجرا میشوند‪.‬‬
‫نحوه تعریف یک رویداد به صورت زیر است ‪:‬‬

‫;‪accessSpecifier event delegateType EventName‬‬

‫‪ accessSpecifier‬سطح دسترسی رویداد است و ‪ event‬یک کلمه کلیدی که در تعریف رویداد به کار میرود‪ delegateType .‬نوع ‪ delegate‬ی که‬
‫مورد استفاده قرار گرفته است را مشخص میکند‪ .‬از ‪ delegate‬برای تشخیص امضای کنترل کننده رویدادی که میتواند به آن متصل شود استفاده میشود‪.‬‬
‫‪ EventName‬هم نامی است که برای رویداد در نظر میگیریم‪ .‬میتوان ارتباط بین ‪ delegate‬و ‪ event‬را به صورت زیر خالصه کرد ‪:‬‬

‫‪249‬‬
‫‪ .1‬یک ‪ delegate‬تعریف میکنیم‪.‬‬
‫‪ .2‬متدهایی که قرار است هنگام وقوع رویداد اجرا شوند را به ‪ delegate‬اضافه میکنیم‪.‬‬
‫‪ .3‬یک رویداد (‪ )event‬ایجاد میکنیم‪.‬‬
‫‪ .4‬یک متد برای اجرای رویداد تعریف میکنیم‪.‬‬
‫‪ .5‬آن دسته از متدهای موجود در ‪ delegate‬را که میخواهیم هنگام وقوع رویداد اجرا شوند یا نشوند را با استفاده از عملگرهای =‪ +‬و =‪ -‬به رویداد‬
‫معرفی میکنیم‪.‬‬
‫‪ .6‬متدی که باعث وقوع رویداد میشود را فراخوانی میکنیم‪.‬‬

‫برای روشن شدن موارد باال به مثال زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫;)(‪3: public delegate void MessageHandler‬‬ ‫‪//step 1‬‬
‫‪4:‬‬
‫‪5: public class Message‬‬
‫{ ‪6:‬‬
‫‪7:‬‬ ‫)(‪public void DisplayMessage‬‬ ‫‪//step 2‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫;)"!‪Console.WriteLine("Hello World‬‬
‫‪10:‬‬ ‫}‬
‫‪11:‬‬
‫‪12:‬‬ ‫;‪public event MessageHandler ShowMessage‬‬ ‫‪//step 3‬‬
‫‪13:‬‬
‫‪14:‬‬ ‫)(‪public void ExecuteEvent‬‬ ‫‪//step 4‬‬
‫‪15:‬‬ ‫{‬
‫‪16:‬‬ ‫;)(‪ShowMessage‬‬
‫‪17:‬‬ ‫}‬
‫} ‪18:‬‬
‫‪19:‬‬
‫‪20: public class Program‬‬
‫{ ‪21:‬‬
‫‪22:‬‬ ‫)(‪public static void Main‬‬
‫‪23:‬‬ ‫{‬
‫‪24:‬‬ ‫;)(‪Message myMessage = new Message‬‬
‫‪25:‬‬ ‫;)‪myMessage.ShowMessage += new MessageHandler(myMessage.DisplayMessage‬‬ ‫‪//step 5‬‬
‫‪26:‬‬
‫‪27:‬‬ ‫;)(‪myMessage.ExecuteEvent‬‬ ‫‪//step 6‬‬
‫‪28:‬‬ ‫}‬
‫} ‪29:‬‬

‫!‪Hello World‬‬
‫در کد باال یک ‪ delegate‬تعریف کردهایم که مقدار برگشتی آن از نوع ‪ void‬بوده و هیچ پارامتری قبول نمیکند (خط ‪ .)3‬این امضاء‪ ،‬همان امضای کنترل‬
‫کننده رویداد میباشد‪ .‬بعد از تعریف ‪ delegate‬یک کالس (خطوط ‪ )5-18‬ایجاد میکنیم‪ .‬یک کنترل کننده رویداد یا متد به نام )(‪ DisplayMessage‬که‬
‫امضای آن شبیه امضای ‪ delegate‬است ایجاد میکنیم (خطوط ‪ .)7-10‬این متد در داخل ‪ delegate‬قرار میگیرد‪ .‬در خط ‪ 12‬یک رویداد و سپس متدی که‬
‫رویداد را به صورت دستی آزاد میکند تعریف میکنیم (‪ .)14-17‬رویدادها نمی توانند در خارج از کالسی که در آن قرار دارند آزاد شوند‪ .‬بنابراین ما از متد ایجاد‬
‫شده برای اجرای غیر مستقیم آنها استفاده میکنیم‪ .‬در داخل متد )(‪ Main‬یک نمونه جدید از کالس ‪ Message‬ایجاد میکنیم (خط ‪ .)24‬در خط بعد یک‬
‫‪250‬‬
‫کنترل کننده رویداد به رویداد ما متصل میشود (خط ‪ .)25‬همانطور که در خط ‪ 25‬مشاهده میکنید‪ ،‬برای اینکه به برنامه بفهمانیم که میخواهیم هنگام وقوع‬
‫رویداد چه متدی از ‪ delegate‬اجرا شود باید به صورت زیر عمل کنیم ‪:‬‬

‫;)‪EventName += new DelegateType(MethodName‬‬

‫به این نکته توجه کنید که استفاده از عملگر ‪ =+‬بدین معنی است که‪ ،‬میخواهیم یک کنترل کننده رویداد به لیست کنترل کنندههای رویداد اضافه نماییم‪ .‬یک‬
‫نمونه از نماینده ‪ (delegate) MessageHandler‬ایجاد کرده و در داخل آن نام کنترل کننده رویداد را ارسال میکنیم (خط ‪ .)25‬وقتی که متد‬
‫)(‪ ExecuteEvent‬فراخوانی میشود‪ ،‬رویداد آزاد و پیغام نمایش داده میشود (خط ‪ .)27‬در آینده به مفید بودن رویداد در هنگام کار با فرمهای ویندوزی و‬
‫صفحات وب پی خواهید برد‪.‬‬

‫متدهای بی نام (‪)Anonymous Methods‬‬

‫متدهای بی نام‪ ،‬متدهایی هستند که در واقع تعریف نمیشوند‪ ،‬بنابراین فقط برای یکبار (‪ )one-time‬مورد استفاده قرار میگیرند‪ .‬این متدها بیشتر در هنگام کار‬
‫با ‪ delegate‬ها به کار میروند‪ .‬در زیر نحوه استفاده از متدهای بی نام نشان داده شده است ‪:‬‬

‫)‪delegate (parameters‬‬
‫{‬
‫‪//Code for the anonymous method‬‬
‫;}‬

‫به عنوان مثال‪ ،‬میتوانیم یک ‪ delegate‬تعریف کرده و سپس یک شیء از آن ایجاد کنیم و متد بی نام را به آن اختصاص دهیم ‪:‬‬

‫;‪using System‬‬

‫;)‪public delegate void MessageDelegate(string message‬‬

‫‪public class Program‬‬


‫{‬
‫)(‪public static void Main‬‬
‫{‬
‫(‪MessageDelegate ShowMessage = new MessageDelegate‬‬
‫)‪delegate(string message‬‬
‫{‬
‫;)‪Console.WriteLine(message‬‬
‫}‬
‫;)‬

‫;)"!‪ShowMessage("Hello World‬‬
‫}‬
‫}‬

‫در مثال فوق ‪ delegate‬دارای نوع برگشتی ‪ void‬و یک پارامتر از نوع رشته میباشد‪ .‬وقتی یک شیء از ‪ delegate‬ایجاد کردیم آنگاه متد بی نام را به آن‬
‫ارسال می کنیم‪ .‬به این نکته توجه کنید که متد بی نام در مثال باال دارای یک پارامتر از نوع رشته مانند ‪ delegate‬است‪ .‬نوع برگشتی به صورت خودکار‬
‫تشخیص داده میشود‪ .‬و اگر نوع برگشتی تشخیص داده نشود متد نوع ‪ void‬را بر میگرداند‪ .‬اگر ‪ delegate‬ایجاد شده توسط شما دارای نوع برگشتی باشد‪،‬‬

‫‪251‬‬
‫متد بی نامی هم که ایجاد میکنید باید دارای دستور ‪ return‬ی باشد که مقدار یک نوع مناسب را برگشت دهد‪ .‬میتوانید کد باال را به صورت سادهتری بنویسید‬
‫‪:‬‬

‫)‪MessageDelegate ShowMessage = delegate(string message‬‬


‫{‬
‫;)‪Console.WriteLine(message‬‬
‫;}‬

‫متدهای بی نام میتوانند هنگام وقوع رویدادها هم به کار روند ‪:‬‬

‫)‪myClass.myEvent += delegate(string message‬‬


‫{‬
‫;)‪Console.WriteLine(message‬‬
‫;}‬

‫به نوعی میتوان گفت که هدف اصلی از تعریف متدهای بی نام‪ ،‬ساده سازی کار با ‪ delegate‬ها میباشد‪.‬‬

‫نوع استنباطی (‪)Type Inference‬‬

‫نوع استنباطی‪ ،‬به متغیر اجازه میدهد که حدس بزند چه نوع داده ای به آن اختصاص داده شده است‪ .‬برای ایجاد انواع استنباطی در سی شارپ از کلمه کلیدی‬
‫‪ var‬استفاده میشود‪.‬‬

‫;‪var myInt = 10‬‬


‫;‪var myDouble = 5.67‬‬
‫;"‪var myString = "Hello‬‬

‫سه متغیر باال انواع ضمنی هستند‪ .‬بدین معنی که‪ ،‬نوع آنها به بسته به مقادیری که به آنها اختصاص داده میشود به صورت اتوماتیک تغییر میکند (مشخص‬
‫میشود)‪ .‬برای مشخص کردن نوع یک متغیر میتوان به سادگی از کلمه کلیدی ‪ var‬استفاده کرد‪ .‬حتی میتوان برای ذخیره نوع ‪ object‬هم از این کلمه‬
‫کلیدی استفاده نمود‪.‬‬

‫;)(‪var sample = new SampleClass‬‬

‫این کلمه کلیدی را می تون برای آرایهها نیز به کار برد ‪:‬‬

‫;} ‪var myArray = new int [] { 1, 2, 3‬‬

‫‪//OR‬‬

‫;} ‪var myArray = new [] { 1, 2, 3‬‬

‫‪252‬‬
‫به این نکته توجه کنید که شما میتوانید بدون ذکر نوع یک متغیر به صورت صریح (مثالً ‪ ،)int myInt‬از کلمه کلیدی ‪ var‬استفاده نمایید‪ ،‬که در نتیجه این‬
‫کار‪ ،‬نوع متغیر بسته به نوع مقداری که به آن اختصاص داده میشود تعیین گردد‪ .‬از آنجاییکه نوع متغیر بسته به نوع مقداری که به آن اختصاص داده میشود‬
‫تعیین میشود‪ ،‬نمیتوان از متغیری که به آن هیچ مقداری ندادهایم همراه با کلمه کلیدی ‪ var‬استفاده کنیم‪ .‬مثالً کد زیر کامپایل نمیشود چون هیچ مقداری به‬
‫متغیر اختصاص داده نشده است‪.‬‬

‫;‪var someVariable‬‬

‫به عنوان آخرین نکته‪ ،‬کلمه کلیدی ‪ var‬برای تعیین نوع (متغیرهای محلی) به کار میرود و نمیتوان از آن به جای نوع برگشتی و نوع پارامترهای یک متد‬
‫استفاده نمود‪.‬‬

‫انواع بی نام (‪)Anonymous Types‬‬

‫در سی شارپ می توان انواع بی نامی تعریف کرد‪ ،‬که یک روش عالی‪ ،‬برای تعریف انواع موقتی‪ ،‬جهت ذخیره انواع دادهها میباشد‪ .‬فرض کنید که‪ ،‬یک کالس‬
‫میخواهید که سه مقدار را در داخل ‪ property‬هایش جای دهد‪.‬‬

‫‪public class Sample‬‬


‫{‬
‫‪public int‬‬ ‫} ;‪Property1 { get; set‬‬
‫} ;‪public double Property2 { get; set‬‬
‫} ;‪public string Property3 { get; set‬‬
‫}‬

‫الزم نیست مانند مثال باال‪ ،‬یک کالس جهت ذخیره سازی ایجاد کنید‪ ،‬بلکه میتوانید یک نوع بی نام ایجاد کنید که ‪ property‬هایی مانند مثال باال را‪ ،‬دارا‬
‫باشد‪.‬‬

‫{ ‪var anonymousType = new‬‬


‫‪Property1 = 10,‬‬
‫‪Property2 = 5.35,‬‬
‫"‪Property3 = "Hello‬‬
‫;}‬

‫برای این کار باید از کلمه کلیدی ‪ var‬استفاده شود‪ .‬دستور ایجاد یک نوع بی نام شبیه به ‪ object initializers‬است با این تفاوت که‪ ،‬در آن از نام کالس‬
‫استفاده نمیکنیم‪ .‬بعد از تعریف میتوان از خواص انواع بی نام استفاده کرد‪.‬‬

‫;)‪Console.WriteLine(anonymousType.Property1‬‬
‫;)‪Console.WriteLine(anonymousType.Property2‬‬
‫;)‪Console.WriteLine(anonymousType.Property3‬‬

‫به این نکته توجه کنید که مقدار دهی فقط یکبار انجام میشود و نمیتوانید مقادیر خواص یک نوع بی نام را ویرایش کنید چون این خواص‪ ،‬خواص فقط خواندنی‬
‫هستند‪.‬‬

‫‪253‬‬
‫متدهای توسعه یافته‬

‫همه متدها‪ ،‬وابسته به کالسی هستند که در آن تعریف شدهاند‪ .‬اما ویژگی توسعه متدها (متدهای توسعه یافته) به شما اجازه میدهد که‪ ،‬متدی ایجاد کنید که‬
‫عالوه بر کالسی که در آن تعریف شده است‪ ،‬به کالسهای دیگر نیز وابسته باشد‪ .‬میخواهیم نحوه استفاده از این ویژگی را به شما آموزش دهیم‪ .‬به کد زیر‬
‫توجه کنید‪ .‬این کد شامل کالسی به نام ‪( Class1‬خطوط ‪ )1-15‬است که سه مقدار از نوع ‪( double‬خط ‪ )3‬را در خود ذخیره میکند‪ ،‬همچنین شامل یک‬
‫سازنده (‪ )5-10‬و یک متد به نام )‪ sum (14-11‬است که جمع سه مقدار ذخیره شده را برگشت میدهد‪.‬‬

‫‪sealed class Class1‬‬


‫{‬
‫;‪private double D1, D2, D3‬‬

‫)‪public Class1(double d1, double d2, double d3‬‬


‫{‬
‫;‪D1 = d1‬‬
‫;‪D2 = d2‬‬
‫;‪D3 = d3‬‬
‫}‬
‫)(‪public double Sum‬‬
‫{‬
‫;‪return D1 + D2 + D3‬‬
‫}‬
‫}‬

‫محدودیت این کالس تا حدی خوب اس ت‪ ،‬اما فرض کنید بخواهید از این کالس بهتر استفاده کنید و متدی دیگری ایجاد کنید که میانگین سه مقدار ذکر شده را‬
‫نیز برگرداند‪ .‬با چیزهایی که در مورد کالسها یاد گرفته اید‪ ،‬چندین روش برای اجرای این کار (اضافه کردن متد) وجود دارد‪ .‬اگر سورس اصلی کالس را در اختیار‬
‫داشته باشید و بتوانید آن را دستکاری کنید به راحتی می توانید متد جدیدی به آن اضافه نمایید‪ .‬اگر به هر دلیلی نتوانید کالس را دستکاری کنید‪ ،‬به عنوان مثال‬
‫کالس ‪ sealed‬باشد‪ ،‬مجبور میشوید که یک متد در کالس دیگر تعریف کنید و آن را به صورت عمومی در دسترس اعضای کالس قرار دهید‪ .‬به عنوان مثال‬
‫یک کالس با نام ‪ ExtendClass1‬با سطح دسترسی ‪ static‬مینویسیم که دارای متدی به نام ‪ Average‬و سطح دسترسی ‪ static‬است‪ .‬به این نکته‬
‫توجه کنید که متد )(‪ Average‬یک نمونه از کالس ‪ Class1‬را به عنوان پارامتر میگیرد‪.‬‬

‫‪static class ExtendClass1‬‬


‫{‬
‫)‪public static double Average(Class1 C1‬‬
‫{‬
‫;‪return C1.Sum() / 3‬‬
‫}‬
‫}‬

‫‪class Program‬‬
‫{‬
‫)(‪static void Main‬‬
‫{‬
‫;)‪Class1 C1 = new Class1(3, 4, 5‬‬
‫;))‪Console.WriteLine("Average: {0}", ExtendClass1.Average(C1‬‬
‫}‬

‫‪254‬‬
‫}‬

‫‪4‬‬
‫با وجودیکه این راه حل کامالً درست است‪ ،‬اما راه حل بهتر این است که متد را در نمونه کالس خودش فراخوانی کنید‪ ،‬تا اینکه یک نمونه از کالس دیگر ایجاد‬
‫کرده و متد را فراخوانی کنید‪ .‬در دو خط کد زیر تفاوت روشن میشود‪ .‬در خط اول متد استاتیک به وسیله یک نمونه از کالس دیگر و در خط دوم متد به وسیله‬
‫یک شیء ایجاد شده از کالس خودش فراخوانی شده است‪.‬‬

‫;)‪ExtendClass1.Average(C1‬‬

‫;)(‪C1.Average‬‬

‫توسعه متدها‪ ،‬به شما اجازه استفاده از روش دوم را میدهد‪ ،‬هر چند که روش اول روشی عادی برای فراخوانی میباشد‪ .‬با اندکی تغییر در تعریف متد‬
‫)(‪ Average‬از روش دوم استفاده کنید‪ .‬تغییری که الزم است در متد بدهید اضافه کردن کلمه کلیدی ‪ this‬قبل از نام نوع در تعریف پارامترها میباشد‪،‬‬
‫همانطور که در زیر نشان داده شده است‪ .‬اضافه کردن کلمه کلیدی ‪ this‬به اولین پارامتر متد ‪ static‬کالس ‪ static‬باعث تبدیل متد عادی کالس‬
‫‪ ExtendClass1‬به متد توسعه یافته کالس ‪ Class1‬میشود‪ .‬حال میتوان از هر دو حالت فراخوانی استفاده نمود‪.‬‬

‫‪static class ExtendClass1‬‬


‫{‬
‫)‪public static double Average(this Class1 C1‬‬
‫{‬
‫‪.....‬‬
‫}‬
‫}‬

‫نکات مهم درباره متد توسعه یافته در زیر ذکر شده است ‪:‬‬

‫کالسی که متد توسعه یافته در آن تعریف شده است باید به صورت ‪ static‬تعریف شود‪.‬‬ ‫•‬
‫خود متد باید به صورت ‪ static‬تعریف شود‪.‬‬ ‫•‬
‫اولین پارامتر متد توسعه یافته باید با کلمه کلیدی ‪ this‬شروع و بعد از این کلمه نام کالسی که میخواهیم متد به آن اضافه شود‪ ،‬ذکر شود‪.‬‬ ‫•‬

‫کد زیر همه برنامه را که شامل کالس ‪ Class1‬و متد توسعه یافته )(‪ Average‬تعریف شده در کالس ‪ ExtendClass1‬را نشان میدهد‪ .‬به این نکته‬
‫توجه کنید که که متد )(‪ Average‬دقیقاً طوری فراخوانی شده است که انگار یک عضو نمونه از کالس ‪ Class1‬است‪ .‬کالسهای ‪ Class1‬و‬
‫‪ ExtendClass1‬هر دو با هم مانند یک کالس با سه متد عمل میکنند‪.‬‬

‫;‪using System‬‬

‫‪namespace ExtensionMethods‬‬
‫{‬

‫‪sealed class Class1‬‬


‫{‬
‫;‪private double D1, D2, D3‬‬

‫)‪public Class1(double d1, double d2, double d3‬‬


‫{‬
‫;‪D1 = d1‬‬

‫‪255‬‬
D2 = d2;
D3 = d3;
}
public double Sum()
{
return D1 + D2 + D3;
}
}

static class ExtendClass1


{
public static double Average(this Class1 C1)
{
return C1.Sum() / 3;
}
}

class Program
{
static void Main()
{
Class1 C1 = new Class1(3, 4, 5);
Console.WriteLine("Sum: {0}", C1.Sum());
Console.WriteLine("Average: {0}", C1.Average());
}
}
}

Sum: 12
Average: 4

)Lambda expressions( ‫عبارات المبدا‬

‫ به عنوان مثال در برنامه زیر از یک متد بی نام که به یک‬.‫) ساده شده دستور زبان متدهای بی نام هستند‬Lambda expressions( ‫عبارات المبدا‬
.‫ ارجاع داده شده است استفاده شده است‬delegate

using System;

public delegate void MessageDelegate(string message);

public class Program


{
public static void Main()
{
MessageDelegate ShowMessage = new MessageDelegate(
delegate(string message)
{
Console.WriteLine(message);
}
256
‫;)‬

‫;)"!‪ShowMessage("Hello World‬‬
‫}‬
‫}‬

‫به وسیله عبارات المبدا میتوان کد باال را به صورت سادهتری نوشت ‪:‬‬

‫;‪using System‬‬

‫;)‪public delegate void MessageDelegate(string message‬‬

‫‪public class Program‬‬


‫{‬
‫)(‪public static void Main‬‬
‫{‬
‫;)‪MessageDelegate ShowMessage = (message) => Console.WriteLine(message‬‬

‫;)"!‪ShowMessage("Hello World‬‬
‫}‬
‫}‬

‫مقایسه متد بی نام و عبارت المبدا ‪:‬‬

‫)‪MyDelegate del = delegate(int x‬‬ ‫; } ;‪{ return x + 1‬‬ ‫متد بی نام ‪//‬‬
‫‪MyLambda‬‬ ‫= ‪lam‬‬ ‫(‬ ‫; } ;‪x) => { return x + 1‬‬ ‫عبارت المبدا ‪//‬‬

‫در عبارت المبدا ابتدا پارامترها را بدون ذکر نوعشان مینویسیم و بعد از عملگر >= استفاده میکنیم‪ .‬سپس دستوراتی را که قرار است اجرا شوند را مینویسیم‪.‬‬
‫نوع پارامترها به صورت خودکار به وسیله کامپایلر تشخیص داده میشود‪ .‬البته امضاء عبارات المبدا باید شبیه به امضاء ‪ delegate‬باشد‪ .‬عبارات المبدا دارای‬
‫اشکال زیادی هستند‪ .‬به عنوان مثال در مثال باال از یک عبارت المبدایی استفاده کردهایم که دارای یک دستور ساده اجرایی است‪ .‬اگر ‪ delegate‬شما برای‬
‫عبارت المبدا هیچ پارامتری نداشته باشد‪ ،‬همه کاری که الزم است نجام دهید این است که هیچ پارامتری در داخل عبارت المبدا قرار ندهید‪.‬‬

‫;)"‪MessageDelegate ShowMessage = () => Console.WriteLine("Hello‬‬

‫به این نکته توجه کنید که شما میتوانید نوع پارامترهای عبارت المبدا را نشان دهید‪.‬‬

‫;)‪MessageDelegate ShowMessage = (string message) => Console.WriteLine(message‬‬

‫اگر نوع یک پارامتر را مشخص کنید‪ ،‬باید نوع سایر پارامترها را نیز مشخص کنید‪ .‬به عنوان مثال نمیتوانید به صورت زیر عمل کنید ‪:‬‬

‫>= )‪MessageDelegate ShowMessage = (string message1, message2‬‬


‫;)‪Console.WriteLine(message1‬‬

‫اگر عبارات المبدای شما دارای چندین دستور اجرایی باشند میتوانید آنها را داخل آکوالد قرار دهید‪ .‬به عبارت المبدایی که دارای آکوالد باشد دستور المبدا می‬
‫گویند‪.‬‬

‫>= )‪MessageDelegate ShowMessage = (message‬‬

‫‪257‬‬
‫{‬
‫;)‪Console.WriteLine(message‬‬
‫;)"‪Console.WriteLine("Some more message‬‬
‫}‬

‫در زیر مثالی از یک عبارت المبدا که دارای مقدار برگشتی است نشان داده شده است ‪:‬‬

‫;} ;‪SampleDelegate GetSquare = (number) => { return number * number‬‬

‫به این نکته توجه کنید که هنگام استفاده از دستور ‪ return‬باید همیشه از دستورات المبدایی استفاده کنید که دارای آکوالد میباشند‪ .‬اگر یک عبارت المبدا فقط‬
‫دارای یک دستور ‪ return‬ساده باشد میتوانید به سادگی آن را به ‪ expression lambda‬تبدیل کنید‪.‬‬

‫;)‪SampleDelegate GetSquare = (number) => (number * number‬‬

‫به این نکته توجه کنید که استفاده از پرانتز در کد باال برای فهم بهتر آن است‪ .‬اگر یک عبارت المبدا دارای یک پارامتر ساده و یک دستور ‪ return‬است‪،‬‬
‫میتوانید برای سادگی بیشتر پرانتزها را حذف نمایید‪:‬‬

‫;‪SampleDelegate GetSquare = number => number * number‬‬

‫ولی اگر یک عبارت المبدا دارای ‪ 2‬یا تعداد بیشتری پارامتر باشد باید انها را داخل پرانتز قرار دهید‪.‬‬

‫;‪SampleDelegate GetSum = (num1, num2) => num1 + num2‬‬

‫عبارت المبدای باال دارای دو پارامتر است و حاصل جمع آنها را بر میگرداند‪.‬‬

‫یک مثال از عبارت المبدا‬

‫با استفاده از عبارات المبدا راحتتر می توان متدهای بی نام را به عنوان آرگومان به دیگر متدها ارسال کرد‪ .‬به مثال زیر توجه کنید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: namespace LambdaDemo‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫;)‪public delegate int Arithmetic(int x, int y‬‬
‫‪6:‬‬
‫‪7:‬‬ ‫‪public class Program‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫)‪public static int GetResult(Arithmetic Operation, int num1, int num2‬‬
‫‪10:‬‬ ‫{‬
‫‪11:‬‬ ‫;)‪return Operation(num1, num2‬‬
‫‪12:‬‬ ‫}‬
‫‪13:‬‬
‫‪14:‬‬ ‫)(‪public static void Main‬‬
‫‪15:‬‬ ‫{‬
‫‪16:‬‬ ‫;)" ‪Console.Write("Enter first number :‬‬

‫‪258‬‬
‫‪17:‬‬ ‫;))(‪int num1 = Convert.ToInt32(Console.ReadLine‬‬
‫‪18:‬‬ ‫;)" ‪Console.Write("Enter second number:‬‬
‫‪19:‬‬ ‫;))(‪int num2 = Convert.ToInt32(Console.ReadLine‬‬
‫‪20:‬‬
‫‪21:‬‬ ‫‪Console.WriteLine("Sum‬‬ ‫;))‪= " + GetResult((x, y) => x + y, num1, num2‬‬
‫‪22:‬‬ ‫;))‪Console.WriteLine("Difference = " + GetResult((x, y) => x - y, num1, num2‬‬
‫‪23:‬‬ ‫‪Console.WriteLine("Product‬‬ ‫;))‪= " + GetResult((x, y) => x * y, num1, num2‬‬
‫‪24:‬‬ ‫‪Console.WriteLine("Quotient‬‬ ‫;))‪= " + GetResult((x, y) => x / y, num1, num2‬‬
‫‪25:‬‬ ‫}‬
‫‪26:‬‬ ‫}‬
‫} ‪27:‬‬

‫‪Enter first number : 5‬‬


‫‪Enter second number: 2‬‬
‫‪Sum‬‬ ‫‪= 7‬‬
‫‪Difference = 3‬‬
‫‪Product‬‬ ‫‪= 10‬‬
‫‪Quotient‬‬ ‫‪= 2‬‬
‫ابتدا در خط ‪ 5‬یک ‪ delegate‬ایجاد میکنیم که دو آرگومان از نوع اعداد صحیح را قبول کرده و یک مقدار صحیح را بر میگرداند‪ .‬سپس از این ‪ delegate‬به‬
‫عنوان یکی از پارامترهای متد )(‪ GetResult‬استفاده میکنیم (خطوط ‪ .)9-12‬دو پارامتر دیگر‪ ،‬دو عدد هستند که همانطور که خواهیم دید در عملیاتهای‬
‫مختلف نقش دارند‪ .‬از آنجاییکه اولین پارامتر یک ‪ delegate‬است‪ ،‬آرگومانی که به آن ارسال میشود باید مرجع یک متد‪ ،‬یا یک متد بی نام و یا یک عبارت‬
‫المبدا باشد‪ .‬با استفاده از عبارت المبدا میتوان کدهای خواناتری نوشت و همچنین کدنویسی را کاهش داد‪ .‬در خطوط ‪ 21-24‬متد ‪ GetResult‬را فراخوانی‬
‫میکنیم‪ .‬توجه کنید که متد در هر فراخوانی یک عبارت المبدا را به عنوان اولین آرگومان قبول میکند‪ .‬اگر از متدهای بی نام استفاده میکردیم‪ ،‬نیاز به کدنویسی‬
‫بیشتری داشتیم و خوانایی آن نیز کمتر میشد‪.‬‬

‫‪Expression-Bodied Members‬‬
‫‪ Expression-bodied members‬یکی از ویژگیهای سی شارپ ‪ 6‬بوده‪ ،‬که به شما اجازه استفاده از المبدا‪ ،‬برای کدنویسی راحتتر متدها‪ ،‬خاصیتها‪،‬‬
‫سربارگذاری عملگرها و ایندکسرهای یک کالس را میدهد‪ .‬با وجود این ویژگی شما به جای نوشتن بدنه یک عضو میتوانید از عالمت المبدا استفاده کنید‪ .‬به‬
‫عنوان مثال‪ ،‬متد زیر را در نظر بگیرید که دو پارامتر را دریافت کرده و جمع آنها را بر میگرداند ‪:‬‬

‫)‪public int GetSum(int x, int y‬‬


‫{‬
‫;‪return x + y‬‬
‫}‬

‫با استفاده از ویژگی ‪ Expression-bodied members‬شما میتوانید کد باال را خالصهتر کرده و به صورت زیر بنویسید ‪:‬‬

‫;‪public int GetSum(int x, int y) => x + y‬‬

‫همانطور که در کد باال مشاهده میکنید‪ ،‬امضای متد را دستکاری نمیکنیم اما بدنه را با عالمت => شروع و سپس عبارتی که جمع دو مقدار را بر میگرداند را‬
‫مینویسیم‪ .‬به این نکته توجه کنید که دیگر الزم نیست از کلمه کلیدی ‪ return‬استفاده کنیم‪ .‬برای تعریف خاصیتها هم میتوانیم از این ویژگی استفاده کنیم‪.‬‬
‫مثالً در کد زیر یک خاصیت فقط خواندنی که نام کامل یک شخص را بر میگرداند تعریف کردهایم ‪:‬‬

‫‪public string FullName‬‬


‫{‬

‫‪259‬‬
‫‪get‬‬
‫{‬
‫;‪return FirstName + " " + LastName‬‬
‫}‬
‫}‬

‫کد باال را به صورت زیر هم میتوان نوشت ‪:‬‬

‫;‪public string FullName => FirstName + " " + LastName‬‬

‫برای متدهایی هم که مقدار برگشتی آنها از نوع ‪ viod‬است و دارای یک خط در بدنه هستند هم میتوان از این ویژگی به صورت زیر استفاده کرد ‪:‬‬

‫;)‪public void PrintMessage(string message) => Console.WriteLine(message‬‬

‫‪ Expression-bodied members‬در تعریف ایندکسرها و سربارگذاری عملگرها هم به کار میرود ‪:‬‬

‫‪// Indexer‬‬
‫;]‪public int this[int index] => InternalCollection[index‬‬

‫‪// Operator Overload‬‬


‫;)‪public static Point operator +(Point p1, Point p2) => new Point(p1.X + p2.X, p1.Y + p2.Y‬‬

‫‪// Conversion Overload‬‬


‫;")}‪public static implicit operator string(Point point) => $"({point.X}, {point.Y‬‬

‫ممکن است که این سؤال برایتان پیش بیاید که آیا میتوان از ویژگی در اعضایی که دارای چندین دستور در بدنه خود هستند استفاده کرد‪ .‬جواب منفی است‪ .‬این‬
‫ویژگی فقط برای اعضایی به کار میرود که دارای یک دستور ساده در بدنه خود هستند‪.‬‬

‫استفاده از کالس های استاتیک در فضای نام‬

‫استفاده از کالسهای استاتیک در فضای نام‪ ،‬یکی از ویژگیهایی است که در ‪ C# 6.0‬گنجانده شده است و به ما اجازه میدهد که از کالسهای استاتیک در‬
‫قسمت فضاهای نامی استفاده کنیم‪ .‬این ویژگی برای توسعه دهندگان بسیار مفید است و از تکرار مکررات جلوگیری میکند‪ .‬همانطور که می دانید در ‪C# 5.0‬‬
‫برای استفاده از متدهای استاتیک یک کالس استاتیک باید ابتدا نام کالس و سپس نقطه و بعد نام متد را بنویسیم‪ .‬مانند )(‪،Console.WriteLine‬‬
‫)(‪ Console.Write‬یا )(‪ .Convert.ToInt32‬اما در ‪ C# 6.0‬کافیست که نام کالس استاتیک را یک بار در قسمت فضای نام وارد کنید و از متدهای‬
‫آن بدون اینکه نام کالس را بیاورید‪ ،‬استفاده کنید‪ .‬به مثال زیر توجه کنید ‪:‬‬

‫‪C# 5.0‬‬

‫;‪using System‬‬

‫‪namespace CsharpNewFeatures‬‬
‫{‬
‫‪class Program‬‬
‫{‬
‫)‪static void Main(string[] args‬‬

‫‪260‬‬
{
Console.WriteLine("Welcome to Visual C# Tutorials!");
}
}
}

C# 6.0

using System;

using static System.Console;

namespace CsharpNewFeatures
{
class Program
{
static void Main(string[] args)
{
WriteLine("Welcome to Visual C# Tutorials!");
}
}
}

‫مقدار دهی اولیه به خصوصیات خودکار‬

‫ معرفی شد که با استفاده از این‬C# 6.0 ‫) یکی از ویژگی های جدید است که در‬Auto property initializer( ‫مقدار دهی اولیه به خصوصیات خودکار یا‬
‫ ها را در سازنده پیشفرض مقدار دهی می‬Property ‫) ما‬C# 5.0( ‫ در نسخه های قبلی‬.‫ ها را در هنگام تعریف مقداردهی کرد‬Property ‫ویژگی می توان‬
: ‫ می توانیم همزمان کار تعریف و مقداردهی را انجام دهیم‬C# 6.0 ‫کردیم اما در‬

C# 5.0

using System;

namespace CsharpNewFeatures
{
class Program
{
public Program()
{
Name = "Jack";
Age = 25;
}

public string Name { get; set; }


public int Age { get; set; }
}

261
}

C# 6.0

using System;

namespace CsharpNewFeatures
{
class Program
{
public string Name { get; set; } = "Jack";
public int Age { get; set; } = 25;
}
}

‫فیلتر استثنائات‬

‫ را‬catch ‫ به ما اجازهی مشخص کردن یک شرط برای یک بالک‬،‫ است که‬C# 6.0 ‫ یک ویژگی جدید در‬Exception filters ‫فیلترهای استثنائات یا‬
‫ جدید است که کار با فیلتر کردن‬C# 6.0 ‫ این ویژگی یکی از بهترین ویژگیهای‬.‫ اجرا میشود‬catch ‫ آنگاه بالک‬،‫ را برگرداند‬true ‫ اگر شرط‬.‫میدهد‬
: ‫ به مثال زیر توجه کنید‬.‫استثنائات را آسان کرده است‬

using System;

namespace CsharpNewFeatures
{
class Program
{
public static void Main()
{
int result;
int x = 5;
int y = 0;

try
{
result = x / y;
}
catch (Exception ex) if (y == 0)
{
Console.WriteLine("An attempt to divide by 0 was detected.");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);

262
‫}‬
‫}‬
‫}‬
‫}‬

‫‪An attempt to divide by 0 was detected.‬‬

‫دستور ‪using‬‬

‫کاربرد اصلی دستور ‪ using‬نابود کردن اشیاء و آزاد کردن فضای حافظه است‪ .‬همانطور که می دانید بعد از ساخت اشیاء و عدم استفاده از آن باید آن را از حافظه‬
‫خارج کنیم تا دوباره آن بخش از حافظه مورد استفاده قرار گیرد‪ .‬اگر چه ‪ garbage collector‬یا زباله روب حافظه این کار را به طور اتوماتیک انجام میدهد‪،‬‬
‫ولی مشخص نیست ‪ garbage collector‬چه زمانی رخ میدهد و تا زمانی که ‪ garbage collector‬کار خود را شروع نکند‪ ،‬همچنان حافظه بال استفاده‬
‫میماند‪ .‬در سی شارپ‪ ،‬شما می توانید هر لحظه که الزم باشد‪ ،‬شیء بال استفاده را از حافظه پاک کنید (اصطالحاٌ ‪ Dispose‬کنید)‪ .‬ساختار کلی دستور ‪using‬‬
‫به صورت زیر است ‪:‬‬

‫)(‪using‬‬
‫{‬
‫‪...‬‬
‫}‬

‫این دستور‪ ،‬به دستور ‪ finally…try‬ترجمه میشود‪ .‬پس دو کد زیر با هم برابرند ‪:‬‬

‫))(‪using (Person person = new Person‬‬


‫{‬
‫‪// Code to execute‬‬
‫}‬

‫;)(‪Person person = new Person‬‬


‫‪try‬‬
‫{‬
‫‪// Code to execute‬‬
‫}‬
‫‪finally‬‬
‫{‬
‫)‪if (person != null‬‬
‫{‬
‫;)(‪person.Dispose‬‬
‫}‬
‫}‬

‫اگر بخواهیم از کالسمان (‪ )Person‬در داخل دستور ‪ using‬استفاده کنیم‪ ،‬باید ابتدا رابط ‪ IDisposable‬را توسط کالسمان پیاده سازی کنیم‪ .‬این رابط‬
‫دارای متد ()‪ Dispose‬میباشد که بعد از دستور ‪ using‬فراخوانی شده و حافظه را از اشیاء بال استفاده پاک میکند‪ .‬به تکه کد زیر توجه کنید ‪:‬‬

‫‪263‬‬
‫;‪using System‬‬

‫‪namespace UsingStatement‬‬
‫{‬
‫‪class Person : IDisposable‬‬
‫{‬
‫)(‪public void Dispose‬‬
‫{‬
‫;)"!‪Console.WriteLine("The Dispose method executed‬‬
‫}‬
‫}‬
‫‪class Program‬‬
‫{‬
‫)‪static void Main(string[] args‬‬
‫{‬
‫))(‪using (Person person = new Person‬‬
‫{‬
‫;)"!‪Console.WriteLine("Using Statement executed‬‬
‫}‬
‫}‬
‫}‬
‫}‬

‫!‪Using Statement executed‬‬


‫!‪The Dispose method executed‬‬
‫همانطور که در خروجی مشاهده میکنید‪ ،‬ابتدا دستور داخل بالک ‪ using‬و سپس دستور داخل متد ()‪ Dispose‬اجرا میشود‪.‬‬

‫مخفی کردن متد (‪)Method Hiding‬‬

‫همانطور که می دانید وقتی یک کالس از کالس دیگر ارث بری میکند‪ ،‬به تمام اعضای ‪ public‬آن کالس دسترسی مییابد‪ .‬اما در برخی موارد‪ ،‬ممکن است‬
‫کالس فرزند دارای متدی باشد که نام و امضای آن شبیه به متدی در کالس پدر باشد‪ .‬حال اگر یک شیء از کالس فرزند ایجاد و متد را فراخوانی کنید‪ ،‬در اصل‬
‫متد کالس فرزند فراخوانی میشود‪ ،‬چونکه کامپایلر سی شارپ به طور خودکار متد کالس پایه را مخفی میکند‪ .‬هر چند که سی شارپ این کار را خودکار انجام‬
‫میدهد ولی بهتر است شما این کار را به صورت دستی و با اضافه کردن کلمه کلیدی ‪ new‬قبل از نوع برگشتی متد انجام دهید‪ ،‬به این کار مخفی کردن متد یا‬
‫‪ Method Hiding‬می گویند‪ ،‬چون که شما عمداً متد کالس پایه را مخفی کردهاید ‪:‬‬

‫;‪1: using System‬‬


‫‪2:‬‬
‫‪3: namespace Program‬‬
‫{ ‪4:‬‬
‫‪5:‬‬ ‫‪class Parent‬‬
‫‪6:‬‬ ‫{‬
‫‪7:‬‬ ‫)(‪public void ShowMessage‬‬
‫‪8:‬‬ ‫{‬
‫‪9:‬‬ ‫;)"‪Console.WriteLine("Method from Base Class‬‬
‫‪10:‬‬ ‫}‬
‫‪11:‬‬ ‫}‬
‫‪12:‬‬

‫‪264‬‬
‫‪13:‬‬ ‫‪class Child : Parent‬‬
‫‪14:‬‬ ‫{‬
‫‪15:‬‬ ‫)(‪public new void ShowMessage‬‬
‫‪16:‬‬ ‫{‬
‫‪17:‬‬ ‫;)"‪Console.WriteLine("Method from Derived Class‬‬
‫‪18:‬‬ ‫}‬
‫‪19:‬‬ ‫}‬
‫‪20:‬‬
‫‪21:‬‬ ‫‪class Program‬‬
‫‪22:‬‬ ‫{‬
‫‪23:‬‬ ‫)‪static void Main(string[] args‬‬
‫‪24:‬‬ ‫{‬
‫‪25:‬‬ ‫;)(‪Child child1 = new Child‬‬
‫‪26:‬‬ ‫;)(‪child1.ShowMessage‬‬
‫‪27:‬‬ ‫}‬
‫‪28:‬‬ ‫}‬
‫} ‪29:‬‬

‫‪Method from Derived Class‬‬


‫ممکن است که این سؤال برای شما پیش آمده باشد که اگر بخواهیم متد کالس پایه را فراخوانی کنیم‪ ،‬باید چکار کنیم؟ سه روش برای این کار وجود دارد‪ .‬اولین‬
‫روش استفاده از کلمه کلیدی ‪ base‬است‪ .‬خط ‪ 17‬را به صورت زیر تغییر داده و برنامه را اجرا کنید ‪:‬‬

‫;)(‪base.ShowMessage‬‬

‫‪Method from Base Class‬‬


‫روش دوم تبدیل صریح شیء ایجاد شده از کالس مشتق به وسیله کالس پایه است‪ .‬خط ‪ 26‬را به صورت زیر تغییر داده و برنامه را اجرا کنید ‪:‬‬

‫;)(‪((Parent)child1).ShowMessage‬‬

‫‪Method from Base Class‬‬


‫روش سوم‪ ،‬دادن ارجاعی از کالس پایه به شیء کالس مشتق است‪ .‬خطوط ‪ 25-26‬را به صورت زیر تغییر داده و برنامه را اجرا کنید ‪:‬‬

‫;)(‪Parent parent = new Child‬‬


‫;)(‪parent.ShowMessage‬‬

‫‪Method from Base Class‬‬


‫حال که با بازنویسی (‪ )Overriding‬و مخفی کردن (‪ )Hiding‬متدها آشنا شدید‪ ،‬بهتر است که با تفاوت این دو آشنا شوید‪ .‬در ‪ Overriding‬اگر یک‬
‫ارجاع از کالس پایه به کالس مشتق بدهیم‪ ،‬متد کالس مشتق ولی در ‪ ،Hiding‬متد کالس پایه فراخوانی میشود‪.‬‬

‫‪ Tuple‬چیست‬

‫‪ Tuple‬یک ساختار دادهای است که‪ ،‬دارای تعدادی خاص و توالی از عناصر میباشد‪ .‬این ساختار دادهای به شما این امکان را میدهد که دادههایی با انواع‬
‫مختلف را بدون اینکه کالس جداگانهای تعریف کنید‪ ،‬در آن قرار دهید‪ .‬پس ‪ Tuple‬از ایجاد کالسهایی که شما برای بسته بندی و انتقال دادهها بین‬
‫‪265‬‬
‫قسمتهای مختلف برنامه تعریف میکنید‪ ،‬جلوگیری میکند‪ .‬فرض کنید که در یک ب رنامه نیاز است که ما دو مقدار را به یک متد ارسال کنیم و در آن متد آنها را‬
‫نمایش دهید‪.‬‬

‫;‪using System‬‬

‫‪namespace TupleDemo‬‬
‫{‬
‫‪public class MethodArguments‬‬
‫{‬
‫} ;‪public int ID { get; set‬‬
‫} ;‪public string Name { get; set‬‬
‫}‬
‫‪class Program‬‬
‫{‬
‫)‪public static void Print(MethodArguments args‬‬
‫{‬
‫;))(‪Console.WriteLine("ID = " + args.ID.ToString‬‬
‫= ‪Console.WriteLine("Name‬‬ ‫;)‪" + args.Name‬‬
‫}‬
‫)‪public static void Main(string[] args‬‬
‫{‬
‫;)(‪MethodArguments arguments = new MethodArguments‬‬
‫;‪arguments.ID = 20‬‬
‫;"‪arguments.Name = "John‬‬

‫;)‪Print(arguments‬‬

‫;)(‪Console.ReadKey‬‬
‫}‬
‫}‬
‫}‬

‫روش کالسیک (بدون استفاده از ‪ )Tuple‬به ا ین صورت است که باید ابتدا یک کالس در برنامه تعریف کنید که دارای دو خاصیت باشد‪ ،‬سپس آرگومان ورودی‬
‫متد را از نوع این کالس تعریف میکنیم‪ .‬حال یک شیء از کالس ایجاد کرده و خاصیتهای آن را مقداردهی میکنیم‪ .‬سپس این شیء را به متد ارسال میکنیم‪.‬‬
‫در متد نیز مقادیر را از خاصیتهای استخراج میکنیم و آنها را نمایش میدهیم‪ .‬این روش برای تعداد زیاد پارامترها نیز جوابگو است و به هر تعداد پارامتری که‬
‫نیاز داشتید می توانید در کالس‪ ،‬خاصیت ایجاد کنید و به شیوه مشابه آنها را مقداردهی و به متد مورد نظر ارسال کنید‪.‬‬
‫مشکالت این رو ش این است که شما برای هر متد باید یک کالس جداگانه تعریف کنید که بسیار وقت گیر و کسل کننده است‪ Tuple .‬این کار را به صورت‬
‫خودکار برای شما انجام میدهد‪ .‬زمانی که شما از ‪ Tuple‬استفاده میکنید‪ ،‬کامپایلر سی شارپ کالس مورد نظر را برای شما در پشت صحنه ایجاد میکند‪ .‬مثال‬
‫باال را این بار با ‪ Tuple‬پیاده سازی میکنیم ‪:‬‬

‫;‪using System‬‬

‫‪namespace TupleDemo‬‬
‫{‬
‫‪class Program‬‬
‫{‬
‫)‪public static void Print(Tuple<int, string> args‬‬
‫{‬
‫;))(‪Console.WriteLine("ID = " + args.Item1.ToString‬‬
‫‪266‬‬
‫= ‪Console.WriteLine("Name‬‬ ‫;)‪" + args.Item2‬‬
‫}‬
‫)‪public static void Main(string[] args‬‬
‫{‬
‫;)"‪var arguments = new Tuple<int, string>(20, "John‬‬
‫;)‪Print(arguments‬‬

‫;)(‪Console.ReadKey‬‬
‫}‬
‫}‬
‫}‬

‫در مثال باال دیگر نیازی به کالس ‪ MethodArguments‬نداریم‪ .‬ورودی متد را از نوع >‪ Tuple<int, string‬تعریف میکنیم‪ .‬در متد ()‪ Main‬یک‬
‫شیء به نام ‪ arguments‬از نوع >‪ Tuple<int, string‬تعریف کردهایم‪ .‬اینطور در نظر بگیرید که با اینکار کامپایلر در پشت صحنه یک کالس شبیه‬
‫کالس ‪ MethodArguments‬تعریف میکند که دارای دو خاصیت میباشد‪ .‬نوع آنها به ترتیب ‪ int‬و ‪ string‬بوده و نام آنها به ترتیب ‪ Item1‬و ‪Item2‬‬
‫است‪ .‬این نامگذاری به صورت خودکار انجام میشود یعنی اگر ما یک پارامتر دیگر مثالً از نوع ‪ bool‬تعریف کنیم کامپایلر نام آنرا ‪ Item3‬میگذارد‪ .‬در ادامه‬
‫این شیء را به متد ()‪ Print‬ارسال میکنیم‪ .‬دقت کنید که نوع پارامتر ‪ Print‬باید دقیقاً شبیه به نوع شیء ایجاد شده (در اینجا >‪ )Tuple<int, string‬باشد‪.‬‬
‫روش دیگر برای ایجاد ‪ Tuple‬استفاده از متد ()‪ Create‬این کالس میباشد‪ .‬در این صورت اگر خط زیر را جایگزین خط باال کنید‪ ،‬همان نتیجه حاصل‬
‫میشود ‪:‬‬

‫;)"‪var arguments = Tuple.Create(20, "John‬‬

‫به این نکته توجه کنید که خروجی متدها میتواند از نوع ‪ Tuple‬باشد ‪:‬‬

‫;‪using System‬‬

‫‪namespace TupleDemo‬‬
‫{‬
‫‪class Program‬‬
‫{‬
‫)(‪public static Tuple<string, string> GetPerson‬‬
‫{‬
‫;)"‪return new Tuple<string, string>("John", "Scith‬‬
‫}‬
‫)‪public static void Main(string[] args‬‬
‫{‬
‫;)(‪var person = GetPerson‬‬

‫;)‪Console.WriteLine(person.Item1 + " " + person.Item2‬‬

‫;)(‪Console.ReadKey‬‬
‫}‬
‫}‬
‫}‬

‫در مثال باال یک متد به نام ()‪ GetPerson‬با نوع خروجی >‪ Tuple<string, string‬تعریف کردهایم‪ .‬در بدنه آن یک شیء از نوع ‪Tuple<string,‬‬
‫>‪ string‬ایجاد کردهایم و آنرا برگشت میدهیم‪ .‬در متد ()‪ Main‬خروجی متد را در متغیر ‪ person‬قرار داده و مقدار خاصیتهای آنرا در خط بعدی نمایش‬
‫میدهیم‪.‬‬
‫‪267‬‬
‫توابع محلی (‪)Local Functions‬‬

‫‪ Local Function‬ها امکان تعریف یک متد در داخل متد دیگر را فراهم می کنند‪ .‬شما می توانید با استفاده از این قابلیت در ‪ C# 7.0‬یک متد را در داخل‬
‫یک مت د موجود تعریف کنید‪ .‬به این نکته توجه کنید که‪ ،‬برای استفاده از این قابلیت های جدید باید آخرین نسخه ویژوال استودیو ( ‪Visual Studio 2015‬‬
‫‪ )Preview 4‬را بر روی سیستم نصب کنید ‪:‬‬

‫)‪private static void Main(string[] args‬‬


‫{‬
‫)‪int LocalFunction(int arg‬‬
‫{‬
‫;‪return 10 * arg‬‬
‫}‬

‫;))‪Console.WriteLine(LocalFunction(10‬‬
‫}‬

‫در مثال باال ‪ ،‬یک متد به نام ‪ LocalFunction‬را در “داخل” بدنه ی متد ‪ Main‬تعریف کرده ایم ‪ ،‬سپس آنرا فراخوانی و خروجی آنرا بر روی صفحه ی‬
‫نمایش چاپ می کنیم‪ .‬در متد های محلی می توانید از متغیرهایی که قبل از تعریف متد ‪ ،‬تعریف شده اند استفاده کنید ‪:‬‬

‫)‪private static void Main(string[] args‬‬


‫{‬
‫;‪int localVar = 10‬‬
‫)‪int LocalFunction(int arg‬‬
‫{‬
‫;‪return localVar * arg‬‬
‫}‬
‫;))‪Console.WriteLine(LocalFunction(10‬‬
‫}‬

‫در مثال باال‪ ،‬در داخل متد محلی از یک متغیر به نام ‪ localVar‬که قبل از متد تعریف شده است استفاده کرده ایم‪.‬‬

‫اشیاء تغییر ناپذیر (‪)Immutable Object‬‬

‫گاهی در برنامه های خود نیاز به ایجاد اشیایی داریم که وضعیت داخلی این اشیاء (مقادیر فیلد ها ‪ ،‬خصیصه ها و …) بعد از ایجاد شی قابل تغییر نباشد‪ .‬در‬
‫چارچوب دات نت‪ ،‬کالس ‪ string‬به این صورت پیاده سازی شده است‪ .‬زمانی که شما یک مقدار رشته ای را در یک متغیر از نوع ‪ string‬قرار می دهید و بعدا‬
‫آن مقدار را تغییر می دهید‪ ،‬کامپایلر ‪ C#‬در پشت صحنه یک شیء با مقدار جدید می سازد و در فیلد مورد نظر قرار می دهد و شیء قبلی را دور می اندازد (توسط‬
‫‪ garbage collector‬پاک می کند) ‪:‬‬

‫‪string Name = "Jason"; // First time it creates a new object.‬‬


‫;"‪Name = "Jack‬‬ ‫‪// It create a new object of string type‬‬

‫‪268‬‬
‫در کد زیر شما یک کالس با نام ‪ Person‬را مشاهده می کنید که شامل دو فیلد با نام های ‪ name‬و ‪ family‬است‪ .‬این دو فیلد به صورت ‪ readonly‬و از‬
‫نوع ‪ string‬تعریف شده اند‪.‬فیلد های ‪ readonly‬تنها می توانند در خط تعریف فیلد یا در سازنده کالس مقدار دهی شوند‪ .‬سپس برای این دو فیلد‪ ،‬خصوصیات‬
‫متناظری ایجاد می کنیم‪ .‬خصوصیت هم فقط از قسمت ‪ get‬تشکیل شده است و نباید قسمت ‪ set‬داشته باشد‪ .‬زیرا کاربر بعد از ایجاد شیء نباید مقادیر درون‬
‫شیء را تغییر دهد‪ .‬مقادیر مورد نظر را از طریق پارامتر های سازنده کالس می گیریم و در فیلدها قرار می دهیم ‪:‬‬

‫‪public class Person‬‬


‫{‬
‫;‪private readonly string name‬‬
‫;‪private readonly string family‬‬

‫‪public string Name‬‬


‫{‬
‫‪get‬‬
‫{‬
‫;‪return this.name‬‬
‫}‬
‫}‬

‫‪public string Family‬‬


‫{‬
‫‪get‬‬
‫{‬
‫;‪return this.family‬‬
‫}‬
‫}‬

‫)‪public Person(string n, string f‬‬


‫{‬
‫;‪this.name = n‬‬
‫;‪this.family = f‬‬
‫}‬
‫}‬

‫نحوه ی استفاده از کالس فوق به صورت زیر می باشد ‪:‬‬

‫;)"‪Person person1 = new Person("Jason", "Statham‬‬

‫;"‪person1.Name = "Jack‬‬

‫;)‪Console.WriteLine(person1.Name + " " + person1.Family‬‬


‫;)(‪Console.ReadKey‬‬

‫در کد باال نمی توانیم بعد از ایجاد شیء مقادیر خصوصیات آن را تغییر دهیم‪.‬زیرا خصوصیات فقط از قسمت ‪ get‬تشکیل شده اند‪ .‬پس خط قرمز در مثال باال غیر‬
‫مجاز می باشد‪.‬‬

‫‪269‬‬

You might also like