C# - Programming
C# - Programming
نویسیزي ﭘﯿ
برنامهﻪ ﺳﺎ
سﺮﻧﺎﻣ جزوه در
سﺑ ﺟ ﺰوه د ر
آموزش C#
Applicationﯽ C#
Console محیطﺮﻧﺎﻣﻪ ﻧﻮﯾﺴ
در ﺑ
محمد عزیزی
ﻧﺮم اﻓﺰار ﮐﺎﻣﭙﯿﻮﺗﺮ
[email protected]
MaziziUni.blogfa.com
1
فهرست موضوعی
ویژوال استودیو
استفاده از IntelliSense
رفع خطاها
توضیحات
کاراکترهای کنترلی
عالمت @
متغیرها
انواع ساده
استفاده از متغیرها
ثابت ها
تبدیل ضمنی
تبدیل صریح
عبارات و عملگرها
عملگرهای ریاضی
عملگرهای منطقی
2
عملگرهای بیتی
تقدم عملگرها
ساختارهای تصمیم
دستور if
دستور else…if
عملگر شرطی
دستور ifچندگانه
دستور Switch
تکرار
حلقه While
حلقه for
آرایه ها
حلقه foreach
متد
پارامترهای out
3
محدوده متغیر
پارامترهای اختیاری
سربارگذاری متدها
بازگشت ()Recursion
نماینده ها()Delegates
شمارش ()Enumeration
ساختار ()Struct
کالس
سازنده ها ()Constructors
مخرب ها ()Destructors
سطح دسترسی
خواص ()Properties
فضای نام
کتابخانه کالس
وراثت
اعضای Static
کالس Static
متدهای مجازی
Boxingو Unboxing
ترکیب ()Containment
سربارگذاری عملگرها
4
عملگر is
رابط ها ()Interfaces
عملگر as
ایندکسر ()Indexer
String Interpolation
ایجاد استثناء
خواص Exception
کالس ArrayList
ایجاد یک کلکسیون
ساخت دیکشنری
Hashtable
5
پیمایشگر ()Iterator
جنریک ها ()Generics
متدهای جنریک
کالس جنریک
Object Initializer
انواع تهی
رویداد ها ()Events
Expression-Bodied Members
فیلتر استثنائات
دستور using
Tupleچیست
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آمده است:
سخت افزار سیستم عامل
DirectX 9-capable video card that runs at 1024 x 768 or higher display resolution Windows Server 2012 R2
مراحل نصب Visual Studio Community 2019آغاز میشود ( Visual Studio Community 2019حدود 5گیگابایت حجم دارد و برای دانلود آن به
یک اینترنت پر سرعت دارید):
10
بعد از گذراندن مرحله باال صفحه ای به صورت زیر باز میشود و از شما می خواهد که لحظاتی را منتظر بمانید:
سپس صفحه ای به صورت زیر به شما نمایش داده می شود ،که شما باید در این صفحه گزینه های .Net Desktop Developmentو Data Storage and
Proccessingرا تیک بزنید:
بعد از فشار دادن دکمه Modifyدر صفحه باال ،شما وارد مراحل نصب ویژوال استودیو می شوید:
بعد از اتمام مراحل نصب ،پیغامی مبنی بر Restartکردن سیستم به شما نمایش داده می شود:
بعد از این مرحله ویژوال استودیو به صورت کامل نصب شده و شما میتوانید از آن استفاده کنید.
اگر دارای یک اکانت مایکروسافت باشید میتوانید تغییراتی که در ویژوال استودیو میدهید را در فضای ابری ذخیره کرده و اگر آن را در کامپیوتر دیگر نصب کنید ،میتوانید با
وارد شده به اکانت خود ،تغییرات را به صورت خودکار بر روی ویژوال استودیویی که تازه نصب شده اعمال کنید .البته میتوانید این مرحله را با زدن دکمه 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نمایش داده میشود و به این صورت ویژوال
استودیو قانونی میشود:
13
در پنجره باال گزینه Windows From Appرا انتخاب کرده و بر روی گزینه Nextکیلک کنید تا صفحه ای به صورت زیر ظاهر شود:
در شکل باال همه چیز را در حالت پیشفرض رها کرده و بر روی دکمه OKکلیک میکنیم تا صفحه زیر نمایان شود:
این صفحه در حکم یک ناحیه برای طراحی فرمهای ویندوزی شما است .فرمهای ویندوزی رابطهای گرافیکی بین کاربر و کامپیوتر هستند و محیط ویندوز نمونه
بارزی از یک رابط گرافیکی یا GUIاست .شما در این صفحه میتوانید کنترلهایی مانند دکمهها ،برچسبها و … به فرمتان اضافه کنید .جزییات بیشتر در مورد
فرمهای ویندوزی و کنترلها و برنامه نویسی شیء گرا در فصل فرمهای ویندوزی آمده است .اما توصیه میشود ابتدا مبانی برنامه نویسی را مطالعه کنید.
14
پروژه و فایلهای مربوط به آن را نشان میدهد .یک Solutionبرنامه ای که توسط شما ساخته شده است را نشان میدهد .ممکن است این برنامه یک پروژه
ساده یا یک پروژه چند بخشی باشد .اگر Solution Explorerدر صفحه شما نمایش داده نمیشود میتوانید از مسیر > View > Other Windows
Solution Explorerو یا با کلیدهای میانبر Ctrl+Alt+Lآنرا نمایان کنید .اگر چندین پروژه در حال اجرا هستند پروژه ای که با خط برجسته ()Bold
نشان داده شده پروژه فعال میباشد و هنگام اجرای برنامه اجرا میشود .اگر بخواهید پروژه ای را که فعال نیست اجرا کنید ،بر روی Solution
Explorerکلیک راست کنید و سپس گزینه Set as StartUp Projectرا انتخاب نمایید Solution Explorer.زیر یک Solutionبا 2پروژه را
نشان میدهد .هر پروژه شامل فایلها و فولدرهای مربوط به خود است.
پنجره خواص ( )Propertiesخواص و رویدادهای مختلف هر آیتم انتخاب شده اعم از فرم ،فایل ،پروژه و کنترل را نشان میدهد .اگر این پنجره مخفی است
میتوانید از مسیر View > Properties Windowیا کلید میانبر F4آنرا ظاهر کنید .در مورد خواص در درسهای آینده مفصل توضیح خواهیم داد.
خاصیتها ،ویژگیها و صفات اشیا را نشان میدهند .به عنوان مثال یک ماشین دارای خواصی مانند رنگ ،سرعت ،اندازه و مدل است.
اگر یک فرم یا کنترل را در صفحه طراحی و یا یک پروژه یا فایل را در SolutionExplorerانتخاب کنید پنجره خواص مربوط به آنها نمایش داده خواهد
شد .این پنجره همچنین دارای رویدادهای مربوط به فرم یا کنترل انتخاب شده میباشد .یک رویداد ( )eventاتفاقی است که در شرایط خاصی پیش میآید
مانند وقتی که بر روی دکمه ( )buttonکلیک و یا متنی را در داخل جعبه متن ( )text boxاصالح میکنیم.
کمبو باکس ( )combo boxشکل باال که با حرف Aنشان داده شده است به شما اجازه میدهد که شی مورد نظرتان (دکمه ،فرم و…) را که میخواهید
خواص آنرا تغییر دهید انتخاب کنید .این کار زمانی مفید است که کنترلهای روی فرم بسیار کوچک یا به هم نزدیک بوده و انتخاب آنها سخت باشد.
در زیر کمبو باکس باال دکمههای مفیدی قرار دارند ( .)Bبرخی از این دکمهها در شرایط خاصی فعال میشوند .دکمه اول خاصیت اشیا را بر اساس دستههای
مختلفی مرتب میکند .دومین دکمه خواص را بر اساس حروف الفبا مرتب میکند که پیشنهاد میکنیم از این دکمه برای دسترسی سریع به خاصیت مورد نظرتان
15
استفاده کنید .سومین دکمه هم وقتی ظاهر می شود که یک کنترل یا یک فرم را در محیط طراحی انتخاب کنیم .این دکمه به شما اجازه دسترسی به خواص فرم
ویا کنترل انتخاب شده را میدهد .چهارمین دکم ه (که به شکل یک رعد و برق نمایش داده شده) رویدادهای فرم ویا کنترل انتخاب شده را میدهد.
در پایین شکل باال توضیحات کوتاهی در مورد خاصیتها و رویدادها نشان داده میشود .بخش اصلی پنجره خواص ( )Cشامل خواص و رویدادها است .در ستون
سمت چپ نام رویداد یا خاصیت و در ستون سمت راست مقدار آنها آمده است .در پایین پنجره خواص جعبه توضیحات ( )Dقرار دارد که توضیحاتی درباره
خواص و رویدادها در آن نمایش داده میشود.
در حالی که هنوز بر روی پنجره کلیک کردهاید و آن را میکشید یک راهنما (فلشی با چهار جهت) ظاهر میشود و شما را در قرار دادن پنجره در محل دلخواه
کمک میکند .به عنوان مثال شما میتوانید پنجره را در باالترین قسمت محیط برنامه قرار دهید .منطقه ای که پنجره قرار است در آنجا قرار بگیرد به رنگ آبی
در میآید:
16
منطقه ای که پنجره قرار است در آنجا قرار بگیرد به رنگ آبی در میآید.
پنجره در قسمت باالی محیط قرار داده شده است .راهنمای صلیب شکل حاوی جعبههای مختلفی است که به شما اجازه میدهد پنجره انتخاب شده را در محل
دلخواه محیط ویژوال سی شارپ قرار دهید .به عنوان مثال پنجره Propertiesرا انتخاب کنید و آنرا به چپترین قسمت صلیب در پنجره نمایش داده شده
نزدیک و رها کنید:
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هستند .در محل کد نویسی کدهایی از قبل نوشته شده که برای شروع شما آنها را
پاک کنید و کدهای زیر را در محل کدنویسی بنویسید:
مثال باال سادهترین برنامه ای است که شما میتوانید در سی شارپ بنویسید .هدف در مثال باال نمایش یک پیغام در صفحه نمایش است .هر زبان برنامه نویسی
دارای قواعدی برای کدنویسی است .اجازه بدهید هر خط کد را در مثال باال توضیح بدهیم .در خط اول فضای نام ( )namespaceتعریف شده است که شامل
کدهای نوشته شده توسط شما است و از تداخل نامها جلوگیری میکند .درباره فضای نام در درسهای آینده توضیح خواهیم داد.
22
در خط دوم آکوالد (}) نوشته شده است .آکوالد برای تعریف یک بلوک کد به کار میرود .سی شارپ یک زبان ساخت یافته است که شامل کدهای زیاد و
ساختارهای فراوانی میباشد .هر آکوالد باز (}) در سی شارپ باید دارای یک آکوالد بسته ({) نیز باشد .همه کدهای نوشته شده از خط 2تا خط 10یک بلوک
کد یا بدنه فضای نام است.
در خط 3یک کالس تعریف شده است .درباره کالسها در فصلهای آینده توضیح خواهیم داد .در مثال باال کدهای شما باید در داخل یک کالس نوشته شود.
بدنه کالس شامل کدهای نوشته شده از خط 4تا 9میباشد .خط 5متد )( Mainیا متد اصلی نامیده میشود .هر متد شامل یک سری کد است که وقتی اجرا
می شوند که متد را صدا بزنیم .درباره متد و نحوه صدا زدن آن در فصول بعدی توضیح خواهیم داد .متد Mainنقطه آغاز اجرای برنامه است .این بدان معناست
که ابتدا تمام کدهای داخل متد )( Mainو سپس بقیه کدها اجرا میشود .درباره متد )( Mainدر فصول بعدی توضیح خواهیم داد .متد )( Mainو سایر
متدها دارای آکوالد و کدهایی در داخل آنها میباشند و وقتی کدها اجرا میشوند که متدها را صدا بزنیم .هر خط کد در سی شارپ به یک سمیکالن (;) ختم
میشود .اگر سمیکالن در آخر خط فراموش شود برنامه با خطا مواجه میشود .مثالی از یک خط کد در سی شارپ به صورت زیر است:
این خط کد پیغام ! 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در سی شارپ با هم فرق
دارند .رشتهها و توضیحات از این قاعده مستثنی هستند که در درسهای آینده توضیح خواهیم داد .مثالً کدهای زیر با خطا مواجه میشوند و اجرا نمیشوند:
تغییر در بزرگی و کوچکی حروف از اجرای کدها جلوگیری میکند .اما کد زیر کامالً بدون خطا است:
{
;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را انتخاب میکنید.
مانند شکل زیر:
اجرای برنامه
وقتی ما برنامه مان را اجرا میکنیم سی شارپ به صورت اتوماتیک کدهای ما را به زبان میانی مایکروسافت کامپایل میکند .دو راه برای اجرای برنامه وجود دارد:
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که ما از آن در برنامه باال استفاده کردیم در این فضای نام قرار دارد.
اینکه قبل از استفاده از هر کالس ابتدا فضای نام آن را مانند کد باال بنویسیم کمی خسته کننده است .خوشبختانه دات نت به ما اجازه میدهد که برای جلوگیری
از تکرار مکررات ،فضاهای نامی را که قرار است در برنامه استفاده کنیم با استفاده از دستور 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
در این صورت با کلیک بر روی آن ،ویژوال استودیو به طور خودکار فضای نام را وارد برنامه میکند:
در مورد فضای نام در درسهای آینده بیشتر توضیح میدهیم .همانطور که قبال هم ذکر شد ،با ورود نسخه های جدید سی شارپ ،قابلیت های جدیدی به این
زبان اضافه می شود که کدنویسی را راحت تر می کنند .مثال کد این درس را در نسخه های جدید می توان به صورت زیر نوشت:
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بنویسید.
IntelliSenseلیستی از کلمات به شما پیشنهاد میدهد که بیشترین تشابه را با نوشته شما دارند .شما میتوانید با زدن دکمه tabگزینه مورد نظرتان را
انتخاب کنید .با تایپ نقطه ( ) .شما با لیست پیشنهادی دیگری مواجه میشوید.
29
اگر بر روی گزینه ای که می خواهید انتخاب کنید لحظه ای مکث کنید ،توضیحی در رابطه با آن مشاهده خواهید کرد مانند شکل باال .هر چه که به پایان کد
نزدیک میشوید لیست پیشنهادی محدود تر میشود .برای مثال با تایپ حرف W،IntelliSenseفقط کلماتی را که دارای حرف Wهستند را نمایش
میدهد.
با تایپ حرفهای بیشتر لیست محدودتر شده و فقط دو کلمه را نشان میدهد.
اگر IntelliSenseنتواند چیزی را که شما تایپ کردهاید پیدا کند ،هیچ چیزی را نمایش نمیدهد .برای ظاهر کردن IntelliSenseکافیست دکمه ترکیبی
Ctrl+Spaceرا فشار دهید .برای انتخاب یکی از متدهایی که دارای چند حالت هستند ،میتوان با استفاده از دکمههای مکان نما (باال و پایین) یکی از حالتها
را انتخاب کرد .مثالً متد )( Writelineهمانطور که در شکل زیر مشاهده میکنید دارای 19حالت نمایش پیغام در صفحه است.
IntelliSenseبه طور هوشمند کدهایی را به شما پیشنهاد میدهد و در نتیجه زمان نوشتن کد را کاهش میدهد .در ویژوال استودیو هر جزء دارای یک آیکون
منحصر به فرد میباشد .در زیر لیست آیکونهای ویژوال استودیو آمده است :
آیکون مربوط به
ثابت)(Constant
خاصیت)(Property
30
آیکون مربوط به
رویداد)(Event
فیلد)(Field
متد)(Method
رابط)(Interface
کالس)(Class
ساختار)(Structure
نوع شمارشی)(Enum
نماینده)(Delegate
فضای نام)(Namespace
کلمه کلیدی)(Keyword
نگران اسامی ذکر شده در جدول باال نباشید .آنها را در درسهای آینده توضیح خواهیم داد .یکی از قابلیتهای جدید که در ویژوال استودیو 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 .دارای چندین ستون است که به طور کامل جزییات
خطاها را نمایش میدهند.
توضیحات ستون
اگر برنامه شما دارای خطا باشد و آن را اجرا کنید با پنجره زیر روبرو میشوید :
34
مربع کوچک داخل پنجره باال را تیک زنید چون دفعات بعد که برنامه شما با خطا مواجه شود دیگر این پنجره به عنوان هشدار نشان داده نخواهد شد .با کلیک بر
روی دکمه Yesبرنامه با وجود خطا نیز اجرا میشود .اما با کلیک بر روی دکمه NOاجرای برنامه متوقف میشود و شما باید خطاهای موجود در پنجره
Error Listرا بر طرف نمایید .یکی دیگر از ویژگیهای مهم پنجره Error Listنشان دادن قسمتی از برنامه است که دارای خطاست .با یک کلیک ساده بر
روی هر کدام خطاهای موجود در پنجره ، Error Listمحل وقوع خطا نمایش داده میشود.
توضیحات
وقتی که کدی تایپ می کنید شاید بخواهید که متنی جهت یادآوری وظیفه آن کد به آن اضافه کنید .در سی شارپ (و بیشتر زبانهای برنامه نویسی) می توان این
کار را با استفاده از توضیحات انجام د اد .توضیحات متونی هستند که توسط کامپایلر نادیده گرفته می شوند و به عنوان بخشی از کد محسوب نمی شوند.
هدف اصلی از ایجاد توضیحات ،باال بردن خوانایی و تشخیص نقش کدهای نوشته شده توسط شما ،برای دیگران است .فرض کنید که می خواهید در مورد یک
کد خاص ،توضیح بدهید ،م ی توانید توضیحات را در باالی کد یا کنار آن بنویسید .از توضیحات برای مستند سازی برنامه هم استفاده می شود .در برنامه زیر نقش
توضیحات نشان داده شده است :
!Hello World
در کد باال ،خط 7یک توضیح درباره خط 8است که به کاربر اعالم می کند که وظیفه خط 8چیست ؟ با اجرای کد باال فقط جمله Hello Worldچاپ شده
و خط 7در خروجی نمایش داده نمی شود چون کامپایلر توضیحات را نادیده می گیرد .توضیحات بر سه نوعند :
•
• >/// <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دارد با این تفاوت که نشانگر ماوس را در همان خط نگه میدارد و خط جدید ایجاد نمیکند .جدول زیر
لیست کاراکترهای کنترلی و کارکرد آنها را نشان میدهد :
کاراکتر کنترلی عملکرد کاراکتر کنترلی عملکرد
36
ما برای استفاده از کاراکترهای کنترلی از بک اسلش (\) استفاده میکنیم .از آنجاییکه \ معنای خاصی به رشتهها میدهد برای چاپ بک اسلش (\) باید از (\\)
استفاده کنیم :
از آنجاییکه از دابل کوتیشن (“) برای نشان دادن رشتهها استفاده میکنیم برای چاپ آن از ”\ استفاده میکنیم :
;)"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
به مثال زیر توجه کنید :
با وجودیکه بهتر است در مثال باال از اسلش ( ) /در cat/dogاستفاده شود ولی عمداً از بک اسلش ( \ ) برای اثبات گفته باال استفاده کردهایم .کامپایلر خطا
ایجاد میکند و به شما میگوید که کاراکتر کنترلی \dقابل تشخیص نیست چون همچین کاراکتر کنترلی وجود ندارد .زمانی وضعیت بدتر خواهد شد که کاراکتر
بعد از بک اسلش کاراکتری باشد که هم جز یک کلمه باشد و هم جز کاراکترهای کنترلی .به مثال زیر توجه کنید :
استفاده از عالمت @ زمانی مناسب است که شما نمیخواهید از عالمت بک اسلش برای نشان دادن یک کارکتر کنترلی استفاده کنید .استفاده از این عالمت
بسیار ساده است و کافی است که قبل از رشته مورد نظر آن را قرار دهید.
از عالمت @ معموالً زمانی استفاده می شود که شما بخواهید مسیر یک دایرکتوری را به عنوان رشته داشته باشید .چون دایرکتوریها دارای تعداد زیادی بک
اسلش هستند و طبیعتاً استفاده از عالمت @ به جای دابل بک اسلش (\\) بهتر است.
;)"System.Console.WriteLine(@"C:\Some Directory\SomeFile.txt
C:\Some Directory\SomeFile.txt
اگر بخواهید یک دابل کوتیشن چاپ کنید به سادگی میتوانید از دو دابل کوتیشن استفاده کنید.
از به کار بردن عالمت @ و کاراکترهای کنترلی به طور همزمان خودداری کنید چون باعث چاپ کاارکتر کنترلی در خروجی میشود.
یکی دیگر از موارد استفاده از عالمت @ چاپ رشتههای چند خطی بدون استفاده از کاراکتر کنترلی \nاست .به عنوان مثال برای چاپ پیغام زیر :
38
یکی از راههای چاپ جمله باال به صورت زیر است :
به نحوه استفاده از \nدر آخر هر جمله توجه کنید .این کاراکتر همانطور که قبالً مشاهده کردید خط جدید ایجاد میکند و در مثال باال باعث میشود که جمله به
چند خط تقسیم شود .از عالمت +هم برای ترکیب رشتهها استفاده میشود .راه دیگر برای نمایش مثال باال در چندین خط استفاده از عالمت @ است
در این حالت کافیست که در هر جا که میخواهید رشته در خط بعد نمایش داده شود دکمه Enterرا فشار دهید
متغیرها
متغیر مکانی از حافظه است که شما میتوانید مقادیری را در آن ذخیره کنید .میتوان آن را به عنوان یک ظرف تصور کرد که دادههای خود را در آن قرار دادهاید.
محتویات این ظرف میتواند پاک شود یا تغییر کند .هر متغیر دارای یک نام نیز هست .که از طریق آن میتوان متغیر را از دیگر متغیرها تشخیص داد و به مقدار
آن دسترسی پیدا کرد .همچنین دارای یک مقدار میباشد که میتواند توسط کاربر انتخاب شده باشد یا نتیجه یک محاسبه باشد .مقدار متغیر میتواند تهی نیز
باشد .متغیر دارای نوع نیز هست بدین معنی که نوع آن با نوع دادهای که در آن ذخیره میشود یکی است .متغیر دارای عمر نیز هست که از روی آن میتوان
تشخیص داد که متغیر باید چقدر در طول برنامه مورد استفاده قرار گیرد .و در نهایت متغیر دارای محدوده استفاده نیز هست که به شما میگوید که متغیر در چه
جای برنامه برای شما قابل دسترسی است .ما از متغیرها به عنوان یک انبار موقتی برای ذخیره داده استفاده میکنیم .هنگامی که یک برنامه ایجاد میکنیم احتیاج
به یک مکان برای ذخیره داده ،مقادیر یا دادههایی که توسط کاربر وارد میشوند ،داریم .این مکان ،همان متغیر است .برای این از کلمه متغیر استفاده میشود
چون ما می توانیم بسته به نوع شرایط هر جا که الزم باشد ،مقدار آن را تغییر دهیم .متغیرها موقتی هستند و فقط موقعی مورد استفاده قرار میگیرند که برنامه در
حال اجراست و وقتی شما برنامه را میبندید محتویات متغیرها نیز پاک میشود .قبالً ذکر شد که به وسیله نام متغیر میتوان به آن دسترسی پیدا کرد .برای
نامگذاری متغیرها باید قوانین زیر را رعایت کرد :
دو متغیر با نامهای myNumberو MyNumberدو متغیر مختلف محسوب میشوند چون یکی از آنها با حرف کوچک mو دیگری با حرف بزرگ M
شروع میشود .شما نمیتوانید دو متغیر را که دقیق شبیه هم هستند را در یک ( scopeمحدوده) تعریف کنید Scope.به معنای یک بلوک کد است که متغیر
در آن قابل دسترسی و استفاده است .در مورد Scopeدر فصلهای آینده بیشتر توضیح خواهیم داد .متغیر دارای نوع هست که نوع دادهای را که در خود ذخیره
میکند را نشان میدهد .معمولترین انواع داده int, double, string, char, float, decimalمیباشند .برای مثال شما برای قرار دادن یک عدد
صحیح در متغیر باید از نوع intاستفاده کنید.
: در جدول زیر هم لیست کلمات کلیدی وابسته ذکر شده که در زمان ها و مکان های خاص مانند کلمات کلیدی رفتار می کنند
40
ascending alias add
انواع ساده
انواع ساده انواعی از دادهها هستند که شامل اعداد ،کاراکترها و رشتهها و مقادیر بولی میباشند .به انواع ساده انواع اصلی نیز گفته میشود چون از آنها برای
ساخت انواع پیچیدهتری مانند کالسها و ساختارها استفاده می شود .انواع ساده دارای مجموعه مشخصی از مقادیر هستند و محدوده خاصی از اعداد را در خود
ذخیره میکنند .در جدول زیر انواع ساده و محدود آنها آمده است :
دامنه نوع
41
به حرف uدر ابتدای برخی از انواع دادهها مثالً ushortتوجه کنید .این بدان معناست که این نوع فقط شامل اعداد مثبت و صفر هستند .جدول زیر انواعی که
مقادیر با ممیز اعشار را میتوانند در خود ذخیره کنند را نشان میدهد :
دقت دامنه تقریبی نوع
برای به خاطر سپردن آنها باید از نماد علمی استفاده شود .نوع دیگری از انواع ساده برای ذخیره دادههای غیر عددی به کار میروند و در جدول زیر نمایش داده
شدهاند :
مقادیر مجاز نوع
charکاراکترهای یونیکد
boolمقدار trueیاfalse
stringمجموعهای از کاراکترهای
نوع charبرای ذخیره کاراکترهای یونیکد استفاده میشود .کاراکترها باید داخل یک کوتیشن ساده قرار بگیرند مانند (’.)‘a
نوع boolفقط میتواند مقادیر درست ( )trueیا نادرست ( )falseرا در خود ذخیره کند و بیشتر در برنامههایی که دارای ساختار تصمیم گیری هستند مورد
میگیرد. قرار استفاده
نوع stringبرای ذخیره گروهی از کاراکترها مانند یک پیغام استفاده میشود .مقادیر ذخیره شده در یک رشته باید داخل دابل کوتیشن قرار گیرند تا توسط
کامپایلر به عنوان یک رشته در نظر گرفته شوند .مانند (”)“massage
استفاده از متغیرها
در مثال زیر نحوه تعریف و مقداردهی متغیرها نمایش داده شده است :
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استفاده کرد .معموالً نام ثابتها را طبق قرارداد با حروف بزرگ مینویسند تا تشخیص آنها در برنامه راحت باشد .نحوه تعریف ثابت در زیر
آمده است :
مثال :
class Program
{
)(public static void Main
{
;const int NUMBER = 1
در این مثال می بینید که مقدار دادن به یک ثابت ،که قبالً مقدار دهی شده برنامه را با خطا مواجه میکند .نکتهی دیگری که نباید فراموش شود این است که
داد. قرار برابر برنامه در شده تعریف متغیرهای دیگر مقدار با را ثابت مقدار نباید
مثال :
;int someVariable
;const int MY_CONST = someVariable
ممکن است این سؤال برایتان پیش آمده باشد که دلیل استفاده از ثابتها چیست؟ اگر مطمئن هستید که مقادیری در برنامه وجود دارند که هرگز در طول برنامه
تغییر نمیکنند بهتر است که آنها را به صورت ثابت تعریف کنید .این کار هر چند کوچک کیفیت برنامه شما را باال میبرد.
تبدیل ضمنی
تبدیل ضمنی متغیرها یک نوع تبدیل است که به طور خودکار توسط کامپایلر انجام میشود .یک متغیر از یک نوع داده میتواند به طور ضمنی به یک نوع دیگر
تبدیل شود به شرطی که مقدار آن از مقدار دادهای که میخواهد به آن تبدیل شود کمتر باشد .به عنوان مثال نوع دادهای byteمیتواند مقادیر 0تا 255را در
خود ذخیره کند و نوع دادهای intمقادیر -2147483648تا 2147483647را شامل میشود .پس میتوانید یک متغیر از نوع byteرا به یک نوع intتبدیل
کنید :
44
در مثال باال مقدار number1برابر 5است در نتیجه متغیر number2که یک متغیر از نوع صحیح است میتواند مقدار number1را در خود ذخیره کند
چون نوع صحیح از نوع بایت بزرگتر است .پس متغیر number1که یک متغیر از نوع بایت است میتواند به طور ضمنی به number2که یک متغیر از نوع
صحیح است تبدیل شود .اما عکس مثال باال صادق نیست.
در این مورد ما با خطا مواجه میشویم .اگر چه مقدار 5متغیر number1در محدوده مقادیر byteیعنی اعداد بین 0-255قرار دارد اما متغیری از نوع بایت
حافظه کمتری نسبت به متغیری از نوع صحیح اشغال میکند .نوع byteشامل 8بیت یا 8رقم دودویی است در حالی که نوع intشامل 32بیت یا رقم باینری
است .یک عدد باینری عددی متشکل از 0و 1است .برای مثال عدد 5در کامپیوتر به عدد باینری 101ترجمه میشود .بنابراین وقتی ما عدد 5را در یک متغیر
از نوع بایت ذخیره میکنیم عددی به صورت زیر نمایش داده میشود :
00000101
و وقتی آن را در یک متغیر از نوع صحیح ذخیره میکنیم به صورت زیر نمایش داده میشود :
00000000000000000000000000000101
بنابراین قرار دادن یک مقدار intدر یک متغیر byteدرست مانند این است که ما سعی کنیم که یک توپ فوتبال را در یک سوراخ کوچک گلف جای دهیم.
برای قرار دادن یک مقدار intدر یک متغیر از نوع byteمیتوان از تبدیل صریح استفاده کرد که در درسهای آینده توضیح داده میشود .نکته دیگری که نباید
فراموش شود این است که شما نمیتوانید اعداد با ممیز اعشار را به یک نوع intتبدیل کنید چون این کار باعث از بین رفتن بخش اعشاری این اعداد میشود.
میتوان یک نوع کاراکتر را به نوع ushortتبدیل کرد چون هر دو دارای طیف مشابهی از اعداد هستند .گرچه هر یک از آنها کامالً متفاوت توسط کامپایلر
ترجمه میشوند .نوع charبه عنوان یک کاراکتر و نوع ushortبه عنوان یک عدد ترجمه میشود.
;)Console.WriteLine(charVar
;)Console.WriteLine(shortVar
c
99
تبدیالتی که کامپایلر به صورت ضمنی میتواند انجام دهد در جدول زیر آمده است :
نوع منبع توانایی تبدیل امن به
short, ushort, int, uint, long, ulong, float, double, decimal byte
45
نوع منبع توانایی تبدیل امن به
double float
نکتهای دیگر که معموالً ابهام بر انگیز است تعین نوع داده است .برای مثال ما چطور بدانیم که مثالً عدد 7از نوع long،uint ،intیا ulongاست؟ برای
این کار باید کاراکترهایی را به انتهای اعداد اضافه کنیم.
در حالت پیشفرض و بدون قرار دادن کاراکتر در انتهای عدد کامپایلر عدد را از نوع صحیح ( )intدر نظر میگیرد .همچنین در حالت پیشفرض کامپایلر اعداد
دسیمال ( )decimalرا اعداد doubleدر نظر میگیرد .شما میتوانید برای نشان دادن اعداد اعشاری floatاز کاراکتر Fو برای نشان دادن اعداد دسیمال از
کاراکتر Mاستفاده کنید.
تبدیل صریح
تبدیل صریح ،نوعی تبدیل است که ،برنامه را مجبور میکند که یک نوع داده را به نوعی دیگر تبدیل کند ،اگر این نوع تبدیل از طریق تبدیل ضمنی انجام نشود.
در هنگام استفاده از این تبدیل باید دقت کرد چون در این نوع تبدیل ممکن است مقادیر اصالح یا حذف شوند .ما میتوانیم این عملیات را با استفاده از Cast
انجام دهیم Cast .فقط نام دیگر تبدیل صریح است و دستور آن به صورت زیر است :
همانطور که قبالً مشاهده کردید نوع intرا نتوانستیم به نوع byteتبدیل کنیم اما اکنون با استفاده از عمل Castاین تبدیل انجام خواهد شد :
46
حال اگر برن امه را اجرا کنید با خطا مواجه نخواهید شد .همانطور که پیشتر اشاره شد ممکن است در هنگام تبدیالت مقادیر اصلی تغییر کنند .برای مثال وقتی که
یک عدد با ممیز اعشار مثالً از نوع doubleرا به یک نوع intتبدیل میکنیم مقدار اعداد بعد از ممیز از بین میروند :
;)Console.WriteLine(number2
5
خروجی کد باال عدد 5است چون نوع دادهای intنمی تواند مقدار اعشار بگیرد .حالت دیگر را تصور کنید .اگر شما بخواهید یک متغیر را که دارای مقداری بیشتر
از محدوده متغیر مقصد هست تبدیل کنید چه اتفاقی می افتد؟ مانند تبدیل زیر که میخواهیم متغیر number1را که دارای مقدار 300است را به نوع بایت
تبدیل کنیم که محدود اعداد بین 0-255را پوشش میدهد.
300 = 00000000000000000000000100101100
= 255 11111111
= 44 00101100
خروجی باال نشان میدهد که بیشترین مقدار byteکه عدد 255است میتواند فقط شامل 8بیت باشد ( )11111111بنابراین فقط 8بیت اول مقدار intبه
متغیر byteانتقال مییابد که شامل ( )00101100یا عدد 44در مبنای 10است .قرار ندادن یک مقدار مناسب در داخل یک متغیر باعث ایجاد یک سرریز
( )overflowمیشود .یک مورد آن سرریز ریاضی نام دارد که در مثال زیر مشاهده میکنید :
گرچه در این تبدیل ،ما دادههایی را از دست میدهیم ،اما کامپایلر کد ما را قبول میکند .برای اینکه برنامه هنگام وقوع سرریز پیغام خطا بدهد میتوان از کلمه
کلیدی checkedاستفاده کرد.
47
تبدیل با استفاده از کالس Convert
کالس Convertیک کالس استاتیک است که میتوان از آن برای تبدیل مقادیر از نوعی به نوع دیگر استفاده کرد .این کالس به نوبه خود دارای متدهایی
برای تبدیل انواع داده به یکدیگر میباشد .در جدول زیر متدها ذکر شدهاند :
نتیجه دستور
در برنامه زیر یک نمونه از تبدیل متغیرها با استفاده از کالس Convertو متدهای آن نمایش داده شده است :
;double x = 9.99
;)int convertedValue = Convert.ToInt32(x
48
;)Console.WriteLine("Original value is: " + x
;)Console.WriteLine("Converted value is: " + convertedValue
عبارات و عملگرها
مثالً X+Y:یک عبارت است که در آن Xو Yعملوند و عالمت +عملگر به حساب میآیند.
زبانهای برنامه نویسی جدید دارای عملگرهایی هستند که از اجزاء معمول زبان به حساب میآیند .سی شارپ دارای عملگرهای مختلفی از جمله عملگرهای
ریاضی ،تخصیصی ،مقایسهای ،منطقی و بیتی میباشد .از عملگرهای ساده ریاضی میتوان به عملگر جمع و تفریق اشاره کرد.
سه نوع عملگر در سی شارپ وجود دارد :
انواع مختلف عملگر که در این بخش مورد بحث قرار میگیرند ،عبارتند از :
عملگرهای ریاضی
سی شارپ از عملگرهای ریاضی برای انجام محاسبات استفاده میکند .جدول زیر عملگرهای ریاضی سی شارپ را نشان میدهد :
نتیجه مثال عملگر دسته
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 %
مثال باال در از نوع عددی استفاده شده است .اما استفاده از عملگرهای ریاضی برای نوع رشتهای نتیجه متفاوتی دارد .همچنین در جمع دو کاراکتر کامپایلر معادل
عددی آنها را نشان میدهد .اگر از عملگر +برای رشتهها استفاده کنیم دو رشته را با هم ترکیب کرده و به هم میچسباند .دیگر عملگرهای سی شارپ
عملگرهای کاهش و افزایش هستند .این عملگرها مقدار 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افزایش یا کاهش مییابد.
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:
برنامه باال نتیجه هر عبارت را نشان میدهد .در این برنامه از متد )( Writelineبرای نشان دادن نتایج در سطرهای متفاوت استفاده شده است .در این
مثال با یک نکته عجیب مواجه میشویم و آن حاصل تقسیم دو عدد صحیح است .وقتی که دو عدد صحیح را بر هم تقسیم کنیم حاصل باید یک عدد
صحیح و فاقد بخش کسری باشد .اما همانطور که مشاهده میکنید اگر فقط یکی از اعداد را به نوع اعشاری doubleتبدیل کنیم (در مثال میبینید)
میشود. داده نشان اعشار صورت به حاصل
برای اینکه ارقام کسری بعد از عدد حاصل دو رقم باشند از } {2:F2استفاده میکنیم F .به معنای تعیین کردن میباشد و در این جا بدین معناست که
عدد را تا دو رقم اعشار نمایش بده .چون خطوط کد طوالنی هستند آنها را در دو خط مینویسیم .سی شارپ خط جدید و فاصله و فضای خالی را نادیده
میگیرد .در خط 29مشاهده میکنید که دو رشته به وسیله عملگر +به هم متصل شدهاند .نتیجه استفاده از عملگر +برای چسباندن دو کلمه “ “ Helloو
“! ”Worldرشته “! ”Hello Worldخواهد بود .به فاصلههای خالی بعد از اولین کلمه توجه کنید اگر آنها را حذف کنید از خروجی برنامه نیز حذف
میشوند.
نوع دیگر از عم لگرهای سی شارپ عملگرهای جایگزینی نام دارند .این عملگرها مقدار متغیر سمت راست خود را در متغیر سمت چپ قرار میدهند .جدول زیر
انواع عملگرهای تخصیصی در سی شارپ را نشان میدهد:
53
نتیجه عملگر مثال
var1 مثالً شکل اصلی کد. استفاده از این نوع عملگرها در واقع یک نوع خالصه نویسی در کد است. برای اتصال دو رشته نیز می توان استفاده کرد+= از عملگر
برنامه زیر. این حالت کدنویسی زمانی کارایی خود را نشان میدهد که نام متغیرها طوالنی باشد. میباشدvar1 = var1 + var2 به صورت+= var2
.چگونگی استفاده از عملگرهای تخصیصی و تأثیر آنها را بر متغیرها نشان میدهد
using System;
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);
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
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
اگر مقادیر دو طرف عملگر true،ANDباشند عملگر ANDمقدار trueرا بر می گرداند .در غیر اینصورت اگر یکی از مقادیر یا هر دوی آنها falseباشند
مقدار falseرا بر می گرداند .در زیر جدول درستی عملگر ANDنشان داده شده است :
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باشد.
عملگر ANDزمانی کارامد است که ما با محدود خاصی از اعداد سرو کار داریم .مثال عبارت 10 <= x <= 100بدین معنی است که xمی تواند مقداری
شامل اعداد 10تا 100را بگیرد .حال برای انتخاب اعداد خارج از این محدوده می توان از عملگر منطقی ANDبه صورت زیر استفاده کرد.
اگر یکی یا هر دو مقدار دو طرف عملگر ، ORدرست ( )trueباشد،عملگر ORمقدار trueرا بر می گرداند .جدول درستی عملگر ORدر زیر نشان داده شده
است :
X || Y Y X
در جدول باال مشاهده می کنید که عملگر ORدر صورتی مقدار falseرا بر میگرداند که مقادیر دو طرف آن falseباشند .کد زیر را در نظر بگیرید.نتیجه این
کد در صورتی درست ( )trueاست که رتبه نهایی دانش آموز ( )finalGradeبزرگتر از 75یا یا نمره نهایی امتحان آن 100باشد.
برخالف دو اپراتور ORو ANDعملگر منطقی NOTیک عملگر یگانی است و فقط به یک عملوند نیاز دارد .این عملگر یک مقدار یا اصطالح بولی را نفی
می کند .مثال اگر عبارت یا مقدار trueباشد آنرا falseو اگر falseباشد آنرا trueمی کند .جدول زیر عملکرد اپراتور NOTرا نشان می دهد :
57
!X X
false true
true false
عملگرهای بیتی
عملگرهای بیتی به شما اجازه میدهند که شکل باینری انواع دادهها را دستکاری کنید .برای درک بهتر این درس توصیه میشود که شما سیستم باینری و نحوه
تبدیل اعداد دهدهی به باینری را از لینک زیر یاد بگیرید :
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نیاز دارد .به این نکته توجه کنید که اعداد باینری از سمت راست به چپ خوانده میشوند .عملگرهای بیتی
سی شارپ در جدول زیر نشان داده شدهاند :
58
عملگر بیتی )&(AND
عملگر بیتی ANDکاری شبیه عملگر منطقی ANDانجام میدهد با این تفاوت که این عملگر بر روی بیتها کار میکند .اگر مقادیر دو طرف آن 1باشد مقدار
1را بر میگرداند و اگر یکی یا هر دو طرف آن صفر باشد مقدار صفر را بر میگرداند .جدول درستی عمگر بیتی ANDدر زیر آمده است:
;)Console.WriteLine(result
1
همانطور که در مثال باال مشاهده میکنید نتیجه عملکرد عملگر ANDبر روی دو مقدار 5و 3عدد یک میشود .اجازه بدهید ببینیم که چطور این نتیجه را به
دست میآید:
5: 00000000000000000000000000000101
3: 00000000000000000000000000000011
------------------------------------
1: 00000000000000000000000000000001
ابتدا دو عدد 5و 3به معادل باینریشان تبدیل میشوند .از آنجاییکه هر عدد صحیح) 32 (intبیت است از صفر برای پر کردن بیتهای خالی استفاده میکنیم .با
استفاده از جدول درستی عملگر بیتی ANDمیتوان فهمید که چرا نتیجه عدد یک میشود.
عملگر بیتی)|(OR
اگر مقادیر دو طرف عملگر بیتی ORهر دو صفر باشند نتیجه صفر در غیر اینصورت 1خواهد شد .جدول درستی این عملگر در زیر آمده است :
59
نتیجه عملگر بیتی ORدر صورتی صفر است که عملوندهای دو طرف آن صفر باشند .اگر فقط یکی از دو عملوند یک باشد نتیجه یک خواهد شد .به مثال زیر
توجه کنید :
;)Console.WriteLine(result
15
وقتی که از عملگر بیتی ORبرای دو مقدار در مثال باال ( 7و )9استفاده میکنیم نتیجه 15میشود .حال بررسی میکنیم که چرا این نتیجه به دست آمده است؟
7: 00000000000000000000000000000111
9: 00000000000000000000000000001001
-----------------------------------
15: 00000000000000000000000000001111
با استفاده از جدول درستی عملگر بیتی ORمیتوان نتیجه استفاده از این عملگر را تشخیص داد .عدد 1111باینری معادل عدد 15صحیح است.
در صورتیکه عملوندهای دو طرف این عملگر هر دو صفر یا هر دو یک باشند نتیجه صفر در غیر اینصورت نتیجه یک میشود .در مثال زیر تأثیر عملگر بیتی
XORرا بر روی دو مقدار مشاهده میکنید :
;)Console.WriteLine(result
2
در زیر معادل باینری اعداد باال ( 5و )7نشان داده شده است.
5: 00000000000000000000000000000101
7: 00000000000000000000000000000111
-----------------------------------
2: 00000000000000000000000000000010
60
با نگاه کردن به جدول درستی عملگر بیتی ،XORمیتوان فهمید که چرا نتیجه عدد 2میشود.
این عملگر یک عملگر یگانی است و فقط به یک عملوند نیاز دارد .در زیر جدول درستی این عملگر آمده است:
NOT X X
0 1
1 0
عملگر بیتی NOTمقادیر بیتها را معکوس میکند .در زیر چگونگی استفاده از این عملگر آمده است :
;)Console.WriteLine(result
به نمایش باینری مثال باال که در زیر نشان داده شده است توجه نمایید.
7: 00000000000000000000000000000111
------------------------------------
-8: 11111111111111111111111111111000
فرض کنید که از یک سبک خاص فونت در برنامهتان استفاده کنید .کدهای مربوط به هر سبک هم در جدول زیر آمده است :
کد سبک
0 Regular
1 Bold
2 Italic
4 Underline
8 Strikeout
توجه کنید که مقدار اولیه صفر بدین معنی است که میخواهید از سبک ( regularعادی) استفاده کنید.
برای نشان دادن فونتها به صورت کلفت ( )Boldاز عملگر بیتی ORاستفاده میشود .توجه کنید که برای فونت Boldباید کد 1را به کار برید.
;fontStyle |= 2
61
برای استفاده از سایر سبکها میتوان به روشهای ذکر شده در باال عمل کرد و فقط کدها را جایگزین کنید .اگر بخواهید یک سبک جدید ایجاد کنید که ترکیبی
از چند سبک باشد میتوانید به سادگی عملگر بیتی ORرا در بین هر سبک فونت قرار دهید مانند مثال زیر :
;fontStyle = 1 | 2 | 4 | 8
این نوع عملگرها به شما اجازه می دهند که بیتها را به سمت چپ یا راست جا به جا کنید .دو نوع عملگر بیتی تغییر مکان وجود دارد که هر کدام دو عملوند قبول
میکنند .عملوند سمت چپ این عملگرها حالت باینری یک مقدار و عملوند سمت راست تعداد جابه جاییبیت ها را نشان میدهد.
مثال دسته عملگر نام
این عملگر بیتهای عملوند سمت چپ را به تعداد nمکان مشخص شده توسط عملوند سمت راست ،به سمت چپ منتقل میکند .به عنوان مثال :
;)Console.WriteLine(result
40
در مثال باال ما بیتهای مقدار 10را دو مکان به سمت چپ منتقل کردهایم ،حال بیایید تأثیر این انتقال را بررسی کنیم :
10: 00000000000000000000000000001010
------------------------------------
40: 00000000000000000000000000101000
مشاهده میکنید که همه بیتها به اندازه دو واحد به سمت چپ منتقل شدهاند .در این انتقال دو صفر از صفرهای سمت چپ کم میشود و در عوض دو صفر به
سمت راست اضافه میشود.
این عملگر شبیه به عمگر تغییر مکان به سمت چپ است با این تفاوت که بیتها را به سمت راست جا به جا میکند .به عنوان مثال :
;)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حاصل میشود .در جدول زیر تقدم
برخی از عملگرهای سی شارپ آمده است :
عملگر تقدم
*, /, %
– +,
>> <<,
=! ==,
&
63
عملگر تقدم
^
|
&&
||
ابتدا عملگرهای با باالترین و سپس عملگرهای با پایینترین حق تقدم در محاسبات تأثیر میگذارند .به این نکته توجه کنید که تقدم عملگرها ++و – به مکان
قرارگیری آنها بستگی دارد (در سمت چپ یا راست عملوند باشند) .به عنوان مثال :
در عبارت اول ابتدا به مقدار numberیک واحد اضافه شده و 4میشود و سپس مقدار جدید با عدد 3جمع میشود و در نهایت عدد 7به دست میآید .در
عبارت دوم مقدار عددی 3به مقدار numberاضافه میشود و عدد 6به دست میآید .سپس این مقدار در متغیر number2قرار میگیرد .و در نهایت مقدار
numberبه 4افزایش مییابد .برای ایجاد خوانایی در تقدم عملگرها و انجام محاسباتی که در آنها از عملگرهای زیادی استفاده میشود از پرانتز استفاده
میکنیم :
در مثال باال ابتدا هر کدام از عباراتی که داخل پرانتز هستند مورد محاسبه قرار میگیرند .به نکتهای در مورد عبارتی که در داخل پرانتز سوم قرار دارد توجه کنید.
در این عبارت ابتدا مقدار داخلیترین پرانتز مورد محاسبه قرار میگیرد یعنی مقدار 6ضربدر 7شده و سپس از 5کم میشود .اگر دو یا چند عملگر با حق تقدم
یکسان موجود باشد ابتدا باید هر کدام از عملگرها را که در ابتدای عبارت میآیند مورد ارزیابی قرار دهید .به عنوان مثال :
;number = 3 * 2 + 8 / 4
هر دو عملگر * و /دارای حق تقدم یکسانی هستند .بنابر این شما باید از چپ به راست آنها را در محاسبات تأثیر دهید .یعنی ابتدا 3را ضربدر 2میکنید و
سپس عدد 8را بر 4تقسیم میکنید .در نهایت نتیجه دو عبارت را جمع کرده و در متغیر numberقرار میدهید.
چارچوب دات نت تعدادی متد برای گرفتن ورودی از کاربر در اختیار شما قرار میدهد .حال میخواهیم درباره متد () ReadLineیکی دیگر از متدهای کالس
Consoleبحث کنیم که یک مقدار رشتهای را از کاربر دریافت میکند .متد () ReadLineفقط مقدار رشتهای را که توسط کاربر نوشته میشود را بر
میگرداند .همانطور که از نام این متد پیداست ،تمام کاراکترهایی را که شما در محیط کنسول تایپ میکنید تا زمانی که دکمه enterرا میزنید میخواند .هر چه
64
که در محیط کنسول تایپ میشود از نوع رشته است .برای تبدیل نوع رشته به انواع دیگر میتوانید از کالس Convertو متدهای آن استفاده کنید .به برنامه
زیر توجه کنید :
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
میتوان با استفاده از دستور ifو یک شرط خاص که باعث ایجاد یک کد میشود یک منطق به برنامه خود اضافه کنید .دستور ifسادهترین دستور شرطی است
که برنامه میگوید اگر شرطی برقرار است کد معینی را انجام بده .ساختار دستور ifبه صورت زیر است :
قبل از اجرای دستور ifابتدا شرط بررسی میشود .اگر شرط برقرار باشد یعنی درست باشد سپس کد اجرا میشود .شرط یک عبارت مقایسهای است.
میتوان از عملگرهای مقایسه ای برای تست درست یا اشتباه بودن شرط استفاده کرد .اجازه بدهید که نگاهی به نحوه استفاده از دستور ifدر داخل برنامه
بیندازیم .برنامه زیر پیغام Hello Worldرا اگر مقدار numberکمتر از 10و Goodbye Worldرا اگر مقدار numberاز 10بزرگتر باشد در
صفحه نمایش میدهد.
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:
در خط 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بنویسید .کافیست که از یک آکوالد برای نشان دادن ابتدا و انتهای دستورات استفاده کنید .همه دستورات
داخل بین آکوالد جز بدنه دستور ifهستند .نحوه تعریف چند دستور در داخل بدنه ifبه صورت زیر است :
در مثال باال اگر مقدار xاز 10بزرگتر باشد دو پیغام چاپ میشود .حال اگر به عنوان مثال آکوالد را حذف کنیم و مقدار xاز 10بزرگتر نباشد مانند کد
زیر :
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
• }
• }
• }
ما از عملگرهای مقایسهای در دستور ifاستفاده کردهایم .ابتدا دو عدد که قرار است با هم مقایسه شوند را به عنوان ورودی از کاربر میگیریم .اعداد با هم
مقایسه میشوند و اگر شرط درست بود پیغامی چاپ می شود .به این نکته توجه داشته باشید که شرطها مقادیر بولی هستند ،بنابراین شما میتوانید نتیجه
یک عبارت را در داخل یک متغیر بولی ذخیره کنید و سپس از متغیر به عنوان شرط در دستور ifاستفاده کنید .اگر مقدار yearبرابر 2000باشد سپس
حاصل عبارت در متغیر isNewMilleniumذخیره میشود .میتوان از متغیر برای تشخیص کد اجرایی بدنه دستور ifاستفاده کرد خواه مقدار متغیر
درست باشد یا نادرست.
دستور 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
آمده است.
در خط 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
عملگر شرطی تنها عملگر سه تایی سی شارپ است که نیاز به سه عملوند دارد ،شرط ،یک مقدار زمانی که شرط درست باشد و یک مقدار زمانی که شرط
نادرست باشد .اجازه بدهید که نحوه استفاده این عملگر را در داخل برنامه مورد بررسی قرار دهیم.
برنامه باال نحوه استفاده از این عملگر شرطی را نشان میدهد .خط یک به صورت زیر ترجمه میشود :اگر مقدار pet1برابر با puppyسپس مقدار dogرا در
type1قرار بده در غیر این صورت مقدار catرا type1قرار بده .خط دو به صورت زیر ترجمه میشود :اگر مقدار pet2برابر با kittenسپس مقدار catرا
در type2قرار بده در غیر این صورت مقدار .dogحال برنامه باال را با استفاده از دستور if elseمینویسیم:
هنگامی که چندین دستور در داخل یک بلوک 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;
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.");
}
}
}
اگر عددی که شما تایپ. بسته به اینکه شما چه چیزی انتخاب میکنید پیغامهای مختلفی چاپ میشود. وابسته است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;
}
}
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:
عملگرهای منطقی به شما اجازه میدهند که چندین شرط را با هم ترکیب کنید .این عملگرها حداقل دو شرط را در گیر میکنند و در آخر یک مقدار بولی را بر
میگردانند .در جدول زیر برخی از عملگرهای منطقی آمده است :
تأثیر عملگر تلفظ مثال
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
: عبارت به کار برد مانند
( مورد بررسی قرار میگیرد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: }
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
}}
نکته مهم اینجاست که شما میتوانید از عملگرهای & و | به عنوان عملگر بیتی استفاده کنید .تفاوت جزئی این عملگرها وقتی که به عنوان عملگر بیتی به کار
می روند این است که دو عملوند را بدون در نظر گرفتن مقدار عملوند سمت چپ مورد بررسی قرار میدهند .به عنوان مثال حتی اگر مقدار عملوند سمت چپ
falseباشد عملوند سمت چپ به وسیله عملگر بیتی )&( ANDارزیابی میشود .اگر شرطها را در برنامه ترکیب کنید استفاده از عملگرهای منطقی AND
)&&( و )||( ORبه جای عملگرهای بیتی )&( ANDو )|( ORبهتر خواهد بود .یکی دیگر از عملگرهای منطقی عملگر )!( NOTاست که نتیجه
یک عبارت را خنثی یا منفی میکند .به مثال زیر توجه کنید:
دستور 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;
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;
}
}
}
شما عدد را وارد میکنید و این عدد در دستور. به اسم هر حیوان یک عدد نسبت داده شده است.برنامه باال به شما اجازه انتخاب حیوان مورد عالقهتان را میدهد
ها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 •
حلقه While
ابتداییترین ساختار تکرار در سی شارپ حلقه Whileاست .ابتدا یک شرط را مورد بررسی قرار میدهد و تا زمانیکه شرط برقرار باشد کدهای درون بلوک اجرا
میشوند .ساختار حلقه Whileبه صورت زیر است :
)while(condition
{
;code to loop
81
}
میبینید که ساختار Whileمانند ساختار ifبسیار ساده است .ابتدا یک شرط را که نتیجه آن یک مقدار بولی است مینویسیم اگر نتیجه درست یا trueباشد
سپس کدهای داخل بلوک Whileاجرا میشوند .اگر شرط غلط یا falseباشد وقتی که برنامه به حلقه Whileبرسد هیچکدام از کدها را اجرا نمیکند .برای
متوقف شدن حلقه باید مقادیر داخل حلقه Whileاصالح شوند.
به یک متغیر شمارنده در داخل بدنه حلقه نیاز داریم .این شمارنده برای آزمایش شرط مورد استفاده قرار میگیرد و ادامه یا توقف حلقه به نوعی به آن وابسته
است .این شمارنده را در داخل بدنه باید کاهش یا افزایش دهیم .در برنامه زیر نحوه استفاده از حلقه Whileآمده است :
!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یکی دیگر از ساختارهای تکرار است .این حلقه بسیار شبیه حلقه whileاست با این تفاوت که در این حلقه ابتدا کد اجرا می شودو سپس
شرط مورد بررسی قرار میگیرد .ساختار حلقه do whileبه صورت زیر است :
do
{
;code to repeat
همانطور که مشاهده میکنید شرط در آخر ساختار قرار دارد .این بدین معنی است که کدهای داخل بدنه حداقل یکبار اجرا میشوند .برخالف حلقه whileکه
اگر شرط نادرست باشد دستورات داخل بدنه اجرا نمیشوند .برای اثبات این موضوع به کدهای زیر توجه کنید :
!Hello World
با اجرای کد باال ،اول دستورات بلوک doاجرا میشوند و بعد مقدار numberبا عدد 10مقایسه میشود .در نتیجه حتی اگر شرط نادرست باشد باز هم قسمت
doحداقل یک بار اجرا میشوند.
اما در کد باال چون اول مقدار numberابتدا مورد مقایسه قرار میگیرد ،اگر شرط درست نباشد دیگر کدی اجرا نمیشود .یکی از موارد برتری استفاده از حلقه
do whileنسبت به حلقه whileزمانی است که شما بخواهید اطالعاتی از کاربر دریافت کنید .در دو کد زیر ،یک عملیات یکسان توسط دو حلقه whileو
do whileپیاده سازی شده است :
83
//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( عملگر
: آمده استfor در زیر یک مثال از حلقه
using System;
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شود ادامه مییابد .حال اگر بخواهید معکوس برنامه باال را پیاده سازی کنید یعنی اعداد از بزرگ به
کوچک چاپ شوند باید به صورت زیر عمل کنید :
کد باال اعداد را از 10به 1چاپ میکند (از بزرگ به کوچک) .مقدار اولیه شمارنده را 10میدهیم و با استفاده از عملگر کاهش (–) برنامهای که شمارش معکوس
را انجام میدهد ایجاد میکنیم .میتوان قسمت شرط و عملگر را به صورتهای دیگر نیز تغییر داد .به عنوان مثال میتوان از عملگرهای منطقی در قسمت شرط
و از عملگرهای تخصیصی در قسمت عملگر افزایش یا کاهش استفاده کرد .همچنین میتوانید از چندین متغیر در ساختار حلقه forاستفاده کنید.
به این نکته توجه کنید که اگر از چندین متغیر شمارنده یا عملگر در حلقه forاستفاده میکنید باید آنها را با استفاده از کاما از هم جدا کنید.
سی شارپ به شما اجازه میدهد که از حلقه ها به صورت تو در تو استفاده کنید .اگر یک حلقه در داخل حلقه دیگر قرار بگیرد ،به آن حلقه تو در تو گفته میشود.
در این نوع حلقهها ،به ازای اجرای یک بار حلقه بیرونی ،حلقه داخلی به طور کامل اجرا میشود .در زیر نحوه ایجاد حلقه تو در تو آمده است :
)while(condition
{
85
)while(condition
{
;)//statement(s
}
;)//statement(s
}
do
{
;)//statement(s
do
{
;)//statement(s
}
;)while(condition
}
;)while(condition
نکتهای که در مورد حلقههای تو در تو وجود دارد این است که ،میتوان از یک نوع حلقه در داخل نوع دیگر استفاده کرد .مثالً میتوان از حلقه forدر داخل حلقه
whileاستفاده نمود .در مثال زیر نحوه استفاده از این حلقهها ذکر شده است .فرض کنید که میخواهید یک مستطیل با 3سطر و 5ستون ایجاد کنید :
86
البته به جای این خط میتوان. یک خط جدید ایجاد میشود و عالمتهای * در خطوط جدید چاپ میشوند،یعنی وقتی حلقه داخلی به طور کامل اجرا شد
. را هم نوشتConsole.WriteLine();
حلقه را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: }
Number 1
Number 2
Number 3
Number 4
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.که نام آرایه را نشان می دهد .هنگام نامگذاری آرایه بهتر است که نام آرایه نشان دهنده نوع آرایه باشد .به عنوان مثال برای نامگذاری
آرایهای که اعداد را در خود ذخیره میکند از کلمه numberاستفاده کنید .طول آرایه که به کامپایلر میگوید شما قصد دارید چه تعداد داده یا مقدار را در آرایه
ذخیره کنید .از کلمه کلیدی newهم برای اختصاص فضای حافظه به اندازه طول آرایه استفاده میشود .برای تعریف یک آرایه که 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مواجه میشوید و بدین معنی است که شما آدرسی را میخواهید که وجود ندارد .یکی
دیگر از راههای تعریف سریع و مقدار دهی یک آرایه به صورت زیر است :
در این روش شما میتوانید فوراً بعد از تعریف اندازه آرایه مقادیر را در داخل آکوالد قرار دهید .به یاد داشته باشید که هر کدام از مقادیر را با استفاده از کاما از هم
جدا کنید .همچنین تعداد مقادیر داخل آکوالد باید با اندازه آرایه تعریف شده برابر باشد .به مثال زیر توجه کنید :
این مثال با مثال قبل هیچ تفاوتی ندارد و تعداد خطهای کدنویسی را کاهش میدهد .شما میتوانید با استفاده از اندیس به مقدار هر یک از اجزاء آرایه دسترسی
یابید و آنها را به دلخواه تغییر دهید .تعداد اجزاء آرایه در مثال باال 5است و ما 5مقدار را در آن قرار میدهیم .اگر تعداد مقادیری که در آرایه قرار میدهیم کمتر یا
بیشتر از طول آرایه باشد با خطا مواجه میشویم .یکی دیگر از راههای تعریف آرایه در زیر آمده است .شما میتوانید هر تعداد عنصر را که خواستید در آرایه قرار
دهید بدون اینکه اندازه آرایه را مشخص کنید .به عنوان مثال :
در این مثال ما 10مقدار را به آرایه اختصاص دادهایم .نکته اینجاست که طول آرایه را تعریف نکردهایم .در این حالت کامپایلر بعد از شمردن تعداد مقادیر داخل
آکوالد طول آرایه را تشخیص میدهد .به یاد داشته باشید که اگر برای آرایه طولی در نظر نگیرید باید برای آن مقدار تعریف کنید در عیر این صورت با خطا مواجه
میشوید :
یک راه بسیار سادهتر برای تعریف آرایه به صورت زیر است :
به سادگی و بدون احتیاج به کلمه کلیدی newمی توان مقادیر را در داخل آکوالد قرار داد .کامپایلر به صورت اتوماتیک با شمارش مقادیر طول آرایه را تشخیص
میدهد.
در زیر مثالی در مورد استفاده از آرایهها آمده است .در این برنامه 5مقدار از کاربر گرفته شده و میانگین آنها حساب میشود:
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:
حلقه foreach
90
حلقه foreachیکی دیگر از ساختارهای تکرار در سی شارپ میباشد که مخصوصاً برای آرایهها ،لیستها و مجموعهها طراحی شده است .حلقه foreachبا
هر بار گردش در بین اجزاء ،مقادیر هر یک از آنها را در داخل یک متغیر موقتی قرار میدهد و شما میتوانید بواسطه این متغیر به مقادیر دسترسی پیدا کنید .در
زیر نحوه استفاده از حلقه foreachآمده است :
temporaryVarمتغیری است که مقادیر اجزای آرایه را در خود نگهداری میکند temporaryVar.باید دارای نوع باشد تا بتواند مقادیر آرایه را در خود
ذخیره کند .به عنوان مثال آرایه شما دارای اعدادی از نوع صحیح باشد باید نوع متغیر موقتی از نوع اعداد صحیح باشد یا هر نوع دیگری که بتواند اعداد صحیح را
در خود ذخیره کند مانند doubleیا .longسپس کلمه کلیدی inو بعد از آن نام آرایه را مینویسیم .در زیر نحوه استفاده از حلقه foreachآمده است :
Number 1
Number 2
Number 3
Number 4
Number 5
در برنامه آرایهای با 5جزء تعریف شده و مقادیر 1تا 5در آنها قرار داده شده است (خط .)7در خط 9حلقه foreachشروع میشود .ما یک متغیر موقتی تعریف
کردهایم که اعداد آرایه را در خود ذخیره میکند .در هر بار تکرار از حلقه foreachمتغیر موقتی ، nمقادیر عددی را از آرایه استخراج میکند .حلقه foreach
مقادیر اولین تا آخرین جزء آرایه را در اختیار ما قرار میدهد.
حلقه foreachبرای دریافت هر یک از مقادیر آرایه کاربرد دارد .بعد از گرفتن مقدار یکی از اجزای آرایه ،مقدار متغیر موقتی را چاپ میکنیم .حلقه foreach
یک ضعف دارد و آن اینست که این حلقه ما را قادر میسازد که به دادهها دسترسی یابیم و یا آنها را بخوانیم ولی اجازه اصالح اجزاء آرایه را نمیدهد .برای درک
این مطلب در مثال زیر سعی شده است که مقدار هر یک از اجزا آرایه افزایش یابد :
اگر برنامه را اجرا کنید با خطا مواجه میشوید .برای اصالح هر یک از اجزا آرایه میتوان از حلقه forاستفاده کرد.
91
;} int[] numbers = { 1, 2, 3
این حلقه یه ضعف دیگر نیز دارد و آن این است که ما نمیتوانیم با استفاده از حلقه foreachبه اندیس عناصر آرایه دست یابیم ،مثالً کد زیر که با حلقه for
نوشته شده است را نمیتوانیم با حلقه foreachپیاده سازی کنیم:
البته این ضعف نیز به نوعی ناشی از غیر قابل ویرایش بودن عناصر آرایه در حلقه foreachاست.
آرایههای چند بعدی آرایههایی هستند که برای دسترسی به هر یک از عناصر آنها باید از چندین اندیس استفاده کنیم .یک آرایه چند بعدی را میتوان مانند یک
جدول با تعدای ستون و ردیف تصور کنید .با افزایش اندیسها اندازه ابعاد آرایه نیز افزایش مییابد و آرایههای چند بعدی با بیش از دو اندیس به وجود میآیند.
نحوه ایجاد یک آرایه با دو بعد به صورت زیر است :
می توان یک آرایه با تعداد زیادی بعد ایجاد کرد به شرطی که هر بعد دارای طول مشخصی باشد .به دلیل اینکه آرایههای سه بعدی یا آرایههای با بیشتر از دو بعد
بسیار کمتر مورد استفاده قرار میگیرند اجازه بدهید که در این درس بر روی آرایههای دو بعدی تمرکز کنیم .در تعریف این نوع آرایه ابتدا نوع آرایه یعنی اینکه
آرایه چه نوعی از انواع داده را در خود ذخیره میکند را مشخص میکنیم .سپس یک جفت کروشه و در داخل کروشهها یک کاما قرار میدهیم .به تعداد کاماهایی
که در داخل کروشه میگذارید توجه کنید .اگر آرایه ما دو بعدی است باید 1کاما و اگر سه بعدی است باید 2کاما قرار دهیم .سپس یک نام برای آرایه انتخاب
کرده و بعد تعریف آنرا با گذاشتن کلمه ، newنوع داده و طول آن کامل میکنیم .در یک آرایه دو بعدی برای دسترسی به هر یک از عناصر به دو مقدار نیاز
داریم یکی مقدار Xو دیگری مقدار Yکه مقدار xنشان دهنده ردیف و مقدار Yنشان دهنده ستون آرایه است البته اگر ما آرایه دو بعدی را به صورت جدول در
نظر بگیریم .یک آرایه سه بعدی را میتوان به صورت یک مکعب تصور کرد که دارای سه بعد است و xطول Y ،عرض و zارتفاع آن است .یک مثال از آرایه
دو بعدی در زیر آمده است :
کد باال به کامپایلر میگوید که فضای کافی به عناصر آرایه اختصاص بده (در این مثال 15خانه) .در شکل زیر مکان هر عنصر در یک آرایه دو بعدی نشان داده
شده است.
92
مقدار 3را به xاختصاص میدهیم چون 3سطر و مقدار 5را به Yچون 5ستون داریم اختصاص میدهیم .چطور یک آرایه چند بعدی را مقدار دهی کنیم؟ چند
راه برای مقدار دهی به آرایهها وجود دارد.
برای راحتی کار میتوان از نوشتن قسمت ] new dataype[,صرف نظر کرد.
و یا میتوان مقدار دهی به عناصر را به صورت دستی انجام داد مانند :
;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 2 3 4 5 6 7 8 9 10 11 12 13 14 15
مشاهده کردید که گردش در میان مقادیر عناصر یک آرایه چند بعدی چقدر راحت است .به وسیله حلقه foreachنمیتوانیم انتهای ردیفها را مشخص کنیم.
برنامه زیر نشان میدهد که چطور از حلقه forبرای خواندن همه مقادیر آرایه و تعیین انتهای ردیفها استفاده کنید.
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کمتر از طول اولین بعد باشد .حال بیایید آنچه را از قبل یاد گرفتهایم در یک
برنامه به کار بریم .این برنامه نمره چهار درس مربوط به سه دانش آموز را از ما میگیرد و معدل سه دانش آموز را حساب میکند.
95
22:
23: Console.WriteLine("Average is {0:F2}",
24: ;)))(total / studentGrades.GetLength(1
25: ;)(Console.WriteLine
26: }
27:
28: }
} 29:
آرایه دندانه دار یا jagged arrayآرایهای چند بعدی است که دارای سطرهای با طول متغیر میباشد .نمونه سادهای از آرایههای چند بعدی ،آرایههای
مستطیلی است که تعداد ستونهای سطرهای آنها برابر است .اما آرایههای دندانه دار دارای سطرهایی با طول متفاوت میباشند .بنابر این آرایههای دندانه دار را
میتوان آرایهای از آرایهها فرض کرد .دستور نوشتن این نوع آرایهها به صورت زیر است :
96
;datatype[][] arrayName
ابتدا datatypeکه نوع آرایه است و سپس چهار کروشه باز و بسته و بعد از آن نام آرایه را مینویسیم .مقداردهی به این آرایهها کمی گیج کننده است .به مثال
زیر توجه کنید :
ابتدا با استفاده از کلمه کلیدی newسطرهای آرایه را مشخص میکنیم .بعد از کلمه کلیدی newنوع آرایه و سپس در اولین کروشه باز و بسته تعداد سطرها را
مینویسیم .سپس تعداد ستونهای هر سطر را با استفاده از اندیس هر سطر به صورت باال مشخص میکنیم .سپس بعد از تعریف ستونها به صورت زیر میتوان
با استفاده از آکوالد مقادیر هر سطر را مشخص کرد :
یک روش بهتر برای مقدار دهی آرایههای دندانه دار به صورت زیر است :
97
کد باال را به صورت سادهتر زیر هم میتوان نوشت :
برای دسترسی به مقدار عناصر یک آرایه دندانه دار باید اندیس سطر و ستون آن را در اختیار داشته باشیم :
]array[row][column
;)]Console.WriteLine(myArrays[1][2
نمیتوان از حلقه foreachبرای دسترسی به عناصر آرایه دندانه دار استفاده کرد :
اگر از حلقه foreachاستفاده کنیم با خطا مواجه میشویم چون عناصر این نوع آرایهها ،آرایه هستند نه عدد یا رشته یا… .برای حل این مشکل باید نوع متغیر
موقتی ( )arrayرا تغییر داده و از حلقه foreachدیگری برای دسترسی به مقادیر استفاده کرد.
در اولین حلقه از خاصیت Lengthبرای به دست آوردن تعداد سطرها (که همان آرایههای یک بعدی هستند) و در دومین حلقه از خاصیت Lengthبرای به
دست آوردن عناصر سطر جاری استفاده میشود.
متد
متدها به شما اجازه میدهند که یک رفتار یا وظیفه را تعریف کنید و مجموعهای از کدها هستند که در هر جای برنامه میتوان از آنها استفاده کرد .متدها دارای
آرگومانهایی هستند که وظیفه متد را مشخص میکنند .متد در داخل کالس تعریف میشود .نمیتوان یک متد را در داخل متد دیگر تعریف کرد .وقتی که شما در
98
برنامه یک متد را صدا میزنید برنامه به قسمت تعریف متد رفته و کدهای آن را اجرا میکند .در سی شارپ متدی وجود دارد که نقطه آغاز هر برنامه است و بدون
آن برنامهها نمیدانند با ید از کجا شروع شوند ،این متد )( Mainنام دارد.
پارامترها همان چیزهایی هستند که متد منتظر دریافت آنها است.
آرگومانها مقادیری هستند که به پارامترها ارسال میشوند.
گاهی اوقات دو کلمه پارامتر و آرگومان به یک منظور به کار میروند .سادهترین ساختار یک متد به صورت زیر است :
به برنامه ساده زیر توجه کنید .در این برنامه از یک متد برای چاپ یک پیغام در صفحه نمایش استفاده شده است :
!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قبل از نام متد استفاده کنیم .مثال زیر یک متد که دارای مقدار برگشتی است را نشان میدهد.
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استفاده کنیم باید تمام کدها دارای مقدار برگشتی باشند.
برای درک بهتر این مطلب به مثال زیر توجه کنید :
101
چون اگر شرط دستور ifنادرست باشد (کاربر مقداری کمتر از 10را وارد کند) برنامه به قسمت elseمیرود تا مقدار صفر را بر گرداند و چون قسمت else
حذف شده است برنامه با خطا مواجه میشود و همچنین اگر دستور returnحذف شود چون برنامه نیاز به مقدار برگشتی دارد پیغام خطا میدهد .و آخرین
مطلبی که در این درس میخواهیم به شما آموزش دهیم این است که شما میتوانید از یک متد که مقدار برگشتی ندارد خارج شوید .حتی اگر از نوع دادهای
voidدر یک متد استفاده میکنید باز هم میتوانید کلمه کلیدی returnرا در آن به کار ببرید .استفاده از returnباعث خروج از بدنه متد و اجرای کدهای بعد
از آن میشود.
پارامترها دادههای خامی هستند که متد آنها را پردازش میکند و سپس اطالعاتی را که به دنبال آن هستید ،در اختیار شما قرار میدهد .فرض کنید پارامترها مانند
اطالعاتی هستند که شما به یک کارمند میدهید که بر طبق آنها کارش را به پایان برساند .یک متد میتواند هر تعداد پارامتر داشته باشد .هر پارامتر میتواند از
انواع مختلف داده باشد .در زیر یک متد با Nپارامتر نشان داده شده است :
102
پارامترها بعد از نام متد و بین پرانتزها قرار میگیرند .بر اساس کاری که متد انجام میدهد میتوان تعداد پارامترهای زیادی به متد اضافه کرد .بعد از فراخوانی یک
متد باید آرگومانهای آن را نیز تأمین کنید .آرگومانها مقادیری هستند که به پارامترها اختصاص داده میشوند .ترتیب ارسال آرگومانها به پارامترها مهم است .عدم
رعایت ترتیب در ارسال آرگومانها باعث به وجود آمدن خطای منطقی و خطای زمان اجرا میشود .اجازه بدهید که یک مثال بزنیم :
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متد را اول با یک رشته و سپس یک عدد خاص فراخوانی میکنیم .حال اگر متد به صورت زیر
فراخوانی میشد :
در برنامه خطا به وجود میآمد چون عدد 100به پارامتری از نوع رشته و رشته ! Hello Worldبه پارامتری از نوع اعداد صحیح ارسال میشد .این نشان
میدهد که ترتیب ارسال آرگومانها به پارامترها هنگام فراخوانی متد مهم است .به مثال 1توجه کنید در آن مثال دو عدد از نوع intبه پارامترها ارسال کردیم که
ترتیب ارسال آنها چون هردو پارامتر از یک نوع بودند مهم نبود .ولی اگر پارامترهای متد دارای اهداف خاصی باشند ترتیب ارسال آرگومانها مهم است.
در مثال باال نشان داده شده است که حتی اگر متد دو آرگومان با یک نوع داده ای قبول کند باز هم بهتر است ترتیب بر اساس تعریف پارامترها رعایت شود .به
عنوان مثال در اولین فراخوانی متد باال اشکالی به چشم نمیآید چون سن شخص 20و قد او 160سانتی متر است .اگر آرگومانها را به ترتیب ارسال نکنیم سن
شخص 160و قد او 20سانتی متر می شود که به واقعیت نزدیک نیست .دانستن مبانی مقادیر برگشتی و ارسال آرگومانها باعث میشود که شما متدهای کارامد
تری تعریف کنید .تکه کد زیر نشان میدهد که شما حتی میتوانید مقدار برگشتی از یک متد را به عنوان آرگومان به متد دیگر ارسال کنید.
)(int MyMethod
{
;return 5
}
104
;)Console.WriteLine(number
}
;))(AnotherMethod(MyMethod
چون مقدار برگشتی متد )( MyMethodعدد 5است و به عنوان آرگومان به متد )( AnotherMethodارسال میشود خروجی کد باال هم عدد 5
است.
یکی دیگر از راه های ارسال آرگومانها استفاده از نام آنهاست .استفاده از نام آرگومانها شما را از به یاد آوری و رعایت ترتیب پارامترها هنگام ارسال آرگومانها
راحت میکند .در عوض شما باید نام پارامترهای متد را به خاطر بسپارید (ولی از آن جاییکه ویژوال استودیو Intellisenseدارد نیازی به این کار نیست).
استفاده از نام آرگومانها خوانایی برنامه را باال میبرد چون شما میتوانید ببینید که چه مقادیری به چه پارامترهایی اختصاص داده شده است.
نامیدن آرگومانها در سی شارپ 2010مطرح شده است و اگر شما از نسخههای قبلی مانند سی شارپ 2008استفاده میکنید نمیتوانید از این خاصیت استفاده
کنید .در زیر نحوه استفاده از نام آرگومانها وقتی که متد فراخوانی میشود نشان داده شده است :
105
Jack's salary is $120.
Andy's salary is $30.
Mark's salary is $75.
// or
// and
همانطور که مشاهده می کنید ابتدا باید آرگومانهای ثابت هنگام فراخوانی متد ذکر شوند .در اولین و دومین فراخوانی در کد باال ،مقدار 30را به عنوان اولین
آرگومان به اولین پارامتر متد یعنی jackاختصاص میدهیم .سومین و چهارمین خط کد باال اشتباه هستند چون آرگومانهای دارای نام قبل از آرگومانهای
ثابت قرار گرفتهاند .قرار گرفتن آرگومانهای دارای نام بعد از آرگومانها ثابت از بروز خطا جلوگیری میکند
آرگومانها را می توان به کمک ارجاع ارسال کرد .این بدان معناست که شما آدرس متغیری را ارسال میکنید نه مقدار آن را .ارسال با ارجاع زمانی مفید است که
شما بخواهید یک آرگومان که دارای مقدار بزرگی است (مانند یک آبجکت) را ارسال کنید .در این حالت وقتی که آرگومان ارسال شده را در داخل متد اصالح
میکند. تغییر هم متد از خارج در آرگومان اصلی مقدار میکنیم
در زیر دستورالعمل پایهای تعریف پارامترها که در آنها به جای مقدار از آدرس استفاده شده است نشان داده شده :
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
107
در برنامه باال دو متد که دارای یک هدف یکسان هستند تعریف شدهاند و آن اضافه کردن عدد 10به مقداری است که به آنها ارسال میشود .اولین متد (خطوط
)9-5دارای یک پارامتر است که نیاز به یک مقدار آرگومان (از نوع )intدارد .وقتی که متد را صدا میزنیم و آرگومانی به آن اختصاص میدهیم (خط ،)24کپی
آرگومان به پارامتر متد ارسال میشود .بنابراین مقدار اصلی متغیر خارج از متد هیچ ارتباطی به پارامتر متد ندارد .سپس مقدار 10را به متغیر پارامتر ()number
میکنیم. چاپ را نتیجه و کرده اضافه
برای اثبات اینکه متغیر numهیچ تغییری نکرده است مقدار آن را یکبار دیگر چاپ کرده و مشاهده میکنیم که تغییری نکرده است .دومین متد (خطوط -15
) 11نیاز به یک مقدار با ارجاع دارد .در این حالت به جای اینکه یک کپی از مقدار به عنوان آرگومان به ان ارسال شود آدرس متغیر به آن ارسال میشود .حال
پارامتر به مقدار اصلی متغیر که زمان فراخوانی متد به آن ارسال میشود دسترسی دارد .وقتی که ما مقدار متغیر پارامتری که شامل آدرس متغیر اصلی است را
تغییر میدهیم (خط )13در واقع مقدار متغیر اصلی در خارج از متد را تغییر دادهایم .در نهایت مقدار اصلی متغیر را وقتی که از متد خارج شدیم را نمایش میدهیم
و مشاهده میشود که مقدار آن واقعاً تغییر کرده است.
پارامترهای out
پارامترهای outپارامترهایی هستند که متغیرهایی را که مقدار دهی اولیه نشدهاند را قبول میکنند .کلمه کلیدی outزمانی مورد استفاده قرار میگیرد که
بخواهیم یک متغیر بدون مقدار را به متد ارسال کنیم .متغیر بدون مقدار اولیه ،متغیری است که مقداری به آن اختصاص داده نشده است .در این حالت متد یک
مقدار به متغیر میدهد .ارسال متغیر مقداردهی نشده به متد زمانی مفید است که شما بخواهید از طریق متد متغیر را مقدار دهی کنید .استفاده از کلمه کلیدی out
باعث ارسال آرگومان به روش ارجاع میشود نه مقدار .به مثال زیر توجه کنید :
myNumber = 10
از کلمه کلیدی outبرای پارامترهای متد استفاده شده است بنابراین میتوانند متغیرهای مقداردهی نشده را قبول کنند .در متد ، Mainخط 15متد را فراخوانی
میکنیم و قبل از آرگومان کلمه کلیدی outرا قرار میدهیم .متغیر مقداردهی نشده ( )myNumberبه متد ارسال میشود و در آنجا مقدار 10به آن اختصاص
داده میشود (خط .)7مقدار myNumberدر خط 17نمایش داده میشود و مشاهده میکنید که مقدارش برابر مقداری است که در داخل متد به آن اختصاص
داده شده است (یعنی .)10استفاده از پارامترهای outبدین معنا نیست که شما همیشه نیاز دارید که آرگومانهای مقداردهی نشده را به متد ارسال کنید بلکه
آرگومانهایی که شامل مقدار هستند را هم میتوان به متد ارسال کرد .این کار درحکم استفاده از کلمه کلیدی refاست.
108
تفاوت refبا outاین است که کلمه کلیدی refبه کامپایلر میگوید که متغیر مقدار دهی اولیه و بعد به متد ارسال شده است ولی outبه کامپایلر میگوید که
متغیر مقدار دهی اولیه نشده و باید در داخل متد مقدار دهی اولیه شود.
همانطور که قبالً هم ذکر شد ،معموالً متد از کلمه کلیدی returnبرای برگشت مقدار استفاده میکند .متاسفانه این کلمه کلیدی فقط میتواند یک مقدار را
برگشت دهد .گاهی اوقات الزم است که یک متد دارای چندین خروجی باشد .اینجاست که از کلمه کلیدی outاستفاده میشود .به مثال زیر توجه کنید :
میتوان آرایهها را به عنوان آرگومان به متد ارسال کرد .ابتدا شما باید پارامترهای متد را طوری تعریف کنید که آرایه دریافت کنند .به مثال زیر توجه کنید.
1
2
3
4
5
مشاهده کردید که به سادگی میتوان با گذاشتن کروشه بعد از نوع دادهای پارامتر یک متد ایجاد کرد که پارامتر آن ،آرایه دریافت میکند .وقتی متد در خط 17
فراخوانی میشود ،آرایه را فقط با استفاده از نام آن و بدون استفاده از اندیس ارسال میکنیم .پس آرایهها هم به روش ارجاع به متدها ارسال میشوند .در خطوط
10-7از حلقه foreachبرای دسترسی به اجزای اصلی آرایه که به عوان آرگومان به متد ارسال کردهایم استفاده میکنیم .در زیر نحوه ارسال یک آرایه به
روش ارجاع نشان داده شده است.
2
3
4
5
6
برنامه باال یک متد را نشان میدهد که یک آرایه را دریافت میکند و به هر یک از عناصر آن یک واحد اضافه میکند .به این نکته توجه کنید که از حلقه
foreachنمی توان برای افزایش مقادیر آرایه استفاده کنیم چون این حلقه برای خواندن مقادیر آرایه مناسب است نه اصالح آنها .در داخل متد ما مقادیر هر یک
110
از اجزای آرایه را افزایش دادهایم ..سپس از متد خارج شده و نتیجه را نشان میدهیم .مشاهده میکنید که هر یک از مقادیر اصلی متد هم اصالح شدهاند .راه دیگر
است. شده فراخوانی متد به مستقیم دهی مقدار متد، به آرایه ارسال برای
به عنوان مثال :
در این روش ما آرایهای تعریف نمیکنیم بلکه مجموعهای از مقادیر را به پارامتر ارسال میکنیم که آنها را مانند آرایه قبول کند .از آنجاییکه در این روش آرایهای
تعریف نکردهایم نمیتوانیم در متد Mainنتیجه را چاپ کنیم .اگر از چندین پارامتر در متد استفاده میکنید همیشه برای هر یک از پارامترهایی که آرایه قبول
کنید. استفاده کروشه جفت یک از میکنند
به عنوان مثال :
به پارامترهای متد باال توجه کنید ،پارامتر اول ( )param1آرگومانی از جنس آرایه قبول میکند ولی پارامتر دوم ( )param2یک عدد صحیح .حال اگر پارامتر
دوم ( )param2هم آرایه قبول میکرد باید برای آن هم از کروشه استفاده میکردیم:
کلمه کلیدی paramsامکان ارسال تعداد دلخواه پارامترهای همنوع و ذخیره آنها در یک آرایه ساده را فراهم میآورد .کد زیر طریقه استفاده از کلمه کلیدی
paramsرا نشان میدهد :
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دار استفاده کنید با خطا مواجه
میشوید .به مثالهای اشتباه و درست زیر توجه کنید :
محدوده متغیر
متغیرها در سی شارپ دارای محدوده ( )scopeهستند .محدوده یک متغیر به شما میگوید که در کجای برنامه میتوان از متغیر استفاده کرد و یا متغیر قابل
دسترسی است .به عنوان مثال متغیری که در داخل یک متد تعریف میشود فقط در داخل بدنه متد قابل دسترسی است .میتوان دو متغیر با نام یکسان در دو متد
مختلف تعریف کرد .برنامه زیر این ادعا را اثبات میکند :
پارامترهای اختیاری
پارامترهای اختیاری همانگونه که از اسمشان پیداست اختیاری هستند و می توان به آنها آرگومان ارسال کرد یا نه .این پارامترها دارای مقادیر پیشفرضی هستند.
اگر به اینگونه پارامترها آرگومانی ارسال نشود از مقادیر پیشفرض استفاده میکنند .به مثال زیر توجه کنید :
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
وقتی متدهای با چندین پارامتر اختیاری فراخوانی میشوند باید به پارامترهایی که از لحاظ مکانی در آخر بقیه پارامترها نیستند مقدار اختصاص داد .به یاد داشته
باشید که نمیتوان برای نادیده گرفتن یک پارامتر به صورت زیر عمل کرد :
اگر بخواهید از یک پارامتر اختیاری که در آخر پارامترهای دیگر نیست رد شوید و آن را نادیده بگیرید باید به از نام پارامترها استفاده کنید.
برای استفاده از نام آرگومانها شما به راحتی میتوانید نام مخصوص پارامتر و بعد از نام عالمت کالن ( ) :و بعد مقدار اختصاص شده به آن را نوشت مانند
( . )optional2: 100متد باال هیچ آرگومانی برای پارامتر اختیاری optional1ندارد بنابراین این پارامتر از مقدار پیشفرضی که در زمان تعریف متد به
آن اختصاص داده شده است استفاده میکند.
سربارگذاری متدها
سربارگذاری متدها به شما اجازه میدهد که دو متد با نام یکسان تعریف کنید که دارای امضاء و تعداد پارامترهای مختلف هستند .برنامه از روی آرگومانهایی که
شما به متد ارسال میکنید به صورت خودکار تشخیص میدهد که کدام متد را فراخوانی کردهاید یا کدام متد مد نظر شماست .امضای یک متد نشان دهنده
ترتیب و نوع پارامترهای آن است .به مثال زیر توجه کنید :
به این نکته توجه کنید که نوع برگشتی و نام پارامترها شامل امضای متد نمیشوند .در مثال زیر نمونهای از سربارگذاری متدها آمده است.
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:
بازگشت ()Recursion
بازگشت فرایندی است که در آن متد مدام خود را فراخوانی میکند تا زمانی که به یک مقدار مورد نظر برسد .بازگشت یک مبحث پیچیده در برنامه نویسی است
و تسلط به آ ن کار راحتی نیست .به این نکته هم توجه کنید که بازگشت باید در یک نقطه متوقف شود وگرنه برای بی نهایت بار ،متد ،خود را فراخوانی میکند .در
این درس یک مثال ساده از بازگشت را برای شما توضیح میدهیم .فاکتوریل یک عدد صحیح مثبت )!(nشامل حاصل ضرب همه اعداد مثبت صحیح کوچکتر
یا مساوی آن میباشد .به فاکتوریل عدد 5توجه کنید.
5! = 5 * 4 * 3 * 2 * 1 = 120
بنابراین برای ساخت یک متد بازگشتی باید به فکر توقف آن هم باشیم .بر اساس توضیح بازگشت ،فاکتوریل فقط برای اعداد مثبت صحیح است .کوچکترین
عدد صحیح مثبت 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را نشان میدهد.
;factorial = 1
این کد از کد معادل بازگشتی آن آسانتر است .از بازگشت در زمینههای خاصی در علوم کامپیوتر استفاده میشود .استفاده از بازگشت حافظه زیادی اشغال میکند
پس اگر سرعت برای شما مهم است از آن استفاده نکنید.
116
)Delegates(نماینده ها
برای تعریف یک. همچنین میتوانند رفتار هر متدی را کپی برداری کنند. ها انواعی هستند که مرجع یک متد را در خود ذخیره میکنندdelegate
بسیار شبیه به تعریف یک متد است با این تفاوت که متد بدنه دارد ولیdelegate تعریف یک. استفاده میشودdelegate از کلمه کلیدیdelegate
ها می گویند که چه نوع متدی را میتوانندdelegate . دقیق ًا مانند متدها دارای نوع برگشتی و مجموعهای از پارامترها هستندdelegate . نداردdelegate
ها را میتوان به عنوان یک ظرف در نظر گرفت که میتوانید هر تعداد متد را که دوست دارید را در داخل آن قرارdelegate به زبان ساده.در خود ذخیره کنند
: نشان داده شده استdelegate در زیر نحوه تعریف. را فراخوانی میکنید تک به تک متدهای داخل آن اجرا میشوندdelegate زمانی که شما.دهید
: و فواید آن نشان داده شده است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:
وقتی یک delegateرا با یک مرجع متد برابر قرار میدهیم باید قبل از نام delegateاز کلمه کلیدی newاستفاده کنیم (مثال باال) .در داخل پرانتز نام
متدی که delegateبه آن مراجعه میکند نشان داده شده است .یک راه بسیار سادهتر برابر قرار دادن نام متد با متغیر delegateاست :
;Operation = Add
;Operation = Subtract
به دستور ifبر میگردیم وقتی شرط درست باشد delegate ،را به متد )( addو هنگامی که شرط نادرست باشد آن را به متد )( Subtractارجاع میدهیم.
اجرای delegateباعث اجرای متدی میشود که delegateبه آن مراجعه میکند .اگر قصد داشته باشید که بیش از یک متد را به delegateاضافه کنید
باید از عملگر = +استفاده نمایید :
کاربرد اصلی delegateها هنگام کار با رویدادها میباشد که در درسهای آینده توضیح میدهیم.
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را بزنید :
C:\Users\VisualCsharp>cd/
شمارش ()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به عنوان نوع دادهای آیتمهای آن اسفاده کنید.
نوع دادهای byteفقط شامل مقادیر بین 0تا 255میشود بنابر این تعداد مقادیر که شما میتوانید به enumerationاضافه کنید محدود میباشد .به نحوه
استفاده از enumerationدر یک برنامه سی شارپ توجه کنید.
Direction: North
121
ابتدا enumerationرا در خطوط 3-9تعریف میکنیم .توجه کنید که enumerationرا خارج از کالس قرار دادهایم .این کار باعث میشود که
enumerationدر سراسر برنامه در دسترس باشد .میتوان enumerationرا در داخل کالس هم تعریف کرد ولی در این صورت فقط در داخل کالس
قابل دسترس است.
class Program
{
enum Direction
{
//Code omitted
}
برنامه را ادامه میدهیم .در داخل بدنه enumerationنام چهار جهت جغرافیایی وجود دارد که هر یک از آنها با 1تا 4مقدار دهی شدهاند .در خط 15یک
متغیر تعریف شده است که مقدار یک جهت را در خود ذخیره میکند .نحوه تعریف آن به صورت زیر است :
;enumType variableName
در اینجا enumTypeنوع داده شمارشی (مثالً Directionیا مسیر) میباشد و variableNameنیز نامی است که برای آن انتخاب کردهایم که در مثال
قبل myDirectionاست .سپس یک مقدار به متغیر myDirectionاختصاص میدهیم (خط .)17برای اختصاص یک مقدار به صورت زیر عمل میکنیم
:
;variable = enumType.value
ابتدا نوع Enumerationسپس عالمت نقطه و بعد مقدار آن (مثالً )Northرا مینویسیم .میتوان یک متغیر را فوراً ،به روش زیر مقدار دهی کرد :
حال در خط 19با استفاده از )( Console.WriteLineمقدار myDirectionرا چاپ میکنیم .توجه کنید که با استفاده از متد )( ToStringمقدار
عددی myDirectionرا به رشته ،جهت چاپ تبدیل میکنیم.
تصور کنید که اگر enumerationنبود شما مجبور بودید که به جای کلمات اعداد را حفظ کنید چون مقادیر enumerationدر واقع اعدادی هستند که با
نام مستعار توسط شما یا هر کس دیگر تعریف میشوند .متغیرهای شمارشی میتوانند به انواع دیگری مانند intیا stringتبدیل شوند .همچنین یک مقدار
رشتهای میتواند به نوع شمارشی معادلش تبدیل شود.
می توان انواع شمارشی را به دیگر مقادیر تبدیل کرد و بالعکس .مقادیر شمارشی در واقع مقادیر عددی هستند که برای درک بهتر آنها ،به هر عدد یک نام
اختصاص داده شده است .به مثال زیر توجه کنید :
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:
Direction: West
در خط 14متغیر myDirectionرا به مقدار Eastنوع شمارشی Directionاختصاص دادهایم .در حالت پیشفرض مقدار Eastدر داخل آیتمهای این داده
شمارشی 1میباشد .در خط 15نشان نحوه تبدیل یک آیتم از نوع شمارشی به عدد صحیح معادل آن به روش تبدیل صریح نشان داده شده است .نحوه این
تبدیل به صورت زیر است:
;variable = (DestinationDataType)enumerationVariable
از آنجاییکه متغیر ( myDirectionCodeخط )15از نوع intاست در نتیجه یک مقدار intباید در آن قرار بگیرد .میتوان به سادگی نوع داده مقصد را در
داخل یک جفت پرانتز قرار داد و آن را کنار نوع شمارشی بگذارید (خط .)15نتیجه یک مقدار تبدیل شده را برگشت میدهد .در خط 19معکوس این کار را انجام
میدهیم .در این خط یک مقدار صحیح را به یک مقدار شمارشی تبدیل میکنیم .مقدار 3را برابر آیتم Westقرار میدهیم.
برای تبدیل آن از روشی شبیه به تبدیل یک نوع شمارشی به صحیح استفاده میکنیم (تبدیل صریح) .به این نکته توجه کنید که اگر عددی را که میخواهید
تبدیل کنید در محدوده انواع شمارشی نباشد ،تبدیل انجام میشود ولی آن آیتم شمارشی و عدد برابر هم نیستند .به عنوان مثال :
;myDirection = (Direction)10
Direction: 10
از آنجاییکه عدد 10مقدار هیچ کدام از آیتمهای نوع شمارشی مثال باال نیست (مقدار آیتمهای نوع شمارشی مثال باال به ترتیب 0و 1و 2و 3میباشد) خروجی
Consoleخود عدد را نشان میدهد ولی اگر به جای عدد 10هر کدام از مقادیر عددی ذکر شده را قرار دهید آیتم معادل با آن نمایش داده خواهد شد.
میتوان یک نوع رشتهای را به نوع شمارشی تبدیل کرد .مثالً میخواهید رشته ” “Westرا به نوع شمارشی Direction.Westمثال باال تبدیل کنید .برای
این کار باید از کالس Enumو فضای نام Systemبه صورت زیر استفاده کنید :
123
;)"Direction myDirection = (Direction)Enum.Parse(typeof(Direction), "West
Direction: West
متد )( Enum.Parseدارای دو پارامتر است .اولین پارامتر نوع شمارشی است .با استفاده از عملگر typeofنوع شمارشی را برگشت میدهیم .دومین پارامتر،
رشتهای است که قرار است به نوع شمارشی تبدیل شود .چون مقدار برگشتی از نوعشی ( )objectاست بنابراین یک تبدیل مناسب نوع شمارشی الزم است .با
این جزییات االن می دانیم که چگونه یک رشته را به نوع شمارشی تبدیل کنیم.
اگر رشتهای که به متد ارسال میکنید جز آیتمهای داده شمارشی نباشد با خطا مواجه میشوید.
ساختار ()Struct
ساختارها یا structانواع دادهای هستند که توسط کاربر تعریف میشوند ( )user-defineو میتوانند دارای فیلد و متد باشند .با ساختارها میتوان نوع دادهای
خیلی سفارشی ایجاد کرد .فرض کنید میخواهیم داده ای ایجاد کنیم که نه تنها نام شخص را ذخیره کند بلکه سن و حقوق ماهیانه او را نیز در خود جای دهد.
برای تعریف یک ساختار به صورت زیر عمل میکنیم :
struct StructName
{
;member1
;member2
;member3
...
;member4
}
برای تعریف ساختار از کلمه کلیدی structاستفاده میشود .برای نامگذاری ساختارها از روش نامگذاری structاستفاده میشود .اعضا در مثال باال
( )member1-5میتوانند متغیر باشند یا متد .در زیر مثالی از یک ساختار آمده است :
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را به جای اینکه به آنها مراجعه کند ،کپی برداری
میکند .کالس یک ساختار ساده است ولی از انواع مرجع به حساب میآید .در مورد کالس در درسهای آینده توضیح خواهیم داد .میتوان به ساختار ،متد هم
اضافه کرد .مثال زیر اصالح شده مثال قبل است.
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پرانتزها را قرار میدهیم و در صورتی که متد به آرگومان هم نیاز داشت در داخل پرانتز آنها را مینویسیم.
برنامه نویسی شیء گرا ( )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
سازندهها متدهای خاصی هستند که وجود آنها برای ساخت اشیا الزم است .آنها به شما اجازه میدهند که مقادیری را به هر یک از اعضای دادهای یک آرایه
اختصاص دهید و کدهایی که را که میخواهید هنگام ایجاد یک شیء اجرا شوند را به برنامه اضافه کنید .اگر از هیچ سازندهای در کالستان استفاده نکنید ،کامپایلر
از سازنده پیشفرض که یک سازنده بدون پارامتر است استفاده میکند .میتوانید در برنامهتان از تعداد زیادی سازنده استفاده کنید که دارای پارامترهای متفاوتی
باشند .در مثال زیر یک کالس که شامل سازنده است را مشاهده میکنید:
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 (خطوط میکند قبول آرگومان سه که است
به این نکته توجه کنید که سازنده درست شبیه به یک متد است با این تفاوت که
سازنده پیشفرض در داخل بدنهاش هیچ چیزی ندارد و وقتی فراخوانی میشود که ما از هیچ سازندهای در کالسمان استفاده نکنیم .در آینده متوجه میشوید که
چطور میتوان مقادیر پیشفرضی به اعضای دادهای اختصاص داد ،وقتی که از یک سازنده پیشفرض استفاده میکنید .به دومین سازنده توجه کنید .اوالً که نام آن
شبیه نام سازنده اول است .سازندهها نیز مانند متدها میتوانند سربارگذاری شوند .حال اجازه دهید که چطور میتوانیم یک سازنده خاص را هنگام تعریف یک
نمونه از کالس فراخوانی کنیم.
در اولین نمونه ایجاد شده از کالس 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
}
همانطور که در مثال باال میبینید سازنده پیشفرض ما چیزی برای اجرا دارد .اگر نمونهای ایجاد کنیم که از این سازنده پیشفرض استفاده کند ،نمونه ایجاد شده
مقادیر پیشفرض سازنده پیشفرض را نشان میدهد.
;)(person1.ShowInformation
Name: No Name
Age: 0 years old
Height: 0cm
راهی دیگر برای ایجاد مقادیر پیشفرض استفاده از کلمه کلیدی 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ارسال میشود.
همانطور که مشاهده میکنید با ایجاد چندین سازنده برای یک کالس ،چندین راه برای ایجاد یک شیء بر اساس دادههایی که نیاز داریم به وجود میآید .در مثال
باال 4نمونه از کالس Personایجاد کردهایم و چهار تغییر در سازنده آن به وجود آوردهایم .سپس مقادیر مربوط به فیلدهای هر نمونه را نمایش میدهیم .یکی
از موراد استفاده از کلمه کلیدی thisبه صورت زیر است .فرض کنید نام پارامترهای متد کالس شما یا سازنده ،شبیه نام یکی از فیلدها باشد.
133
این نوع کدنویسی ابهام بر انگیز است و کامپایلر نمیتواند متغیر را تشخیص داده و مقداری به آن اختصاص دهد .اینجاست که از کلمه کلیدی thisاستفاده
میکنیم.
قبل از هر فیلدی کلمه کلیدی thisرا مینویسیم و نشان میدهیم که این همان چیزی است که میخواهیم به آن مقداری اختصاص دهیم .کلمه کلیدی
thisارجاع یک شیء به خودش را نشان میدهد.
مخرب ها ()Destructors
مخربها نقطه مقابل سازندهها هستند .مخربها متدهای خاصی هستند که هنگام تخریب یک شیء فراخوانی میشوند .اشیا از حافظه کامپیوتر استفاده میکنند و
اگر پاک نشوند ممکن است با کمبود حافظه مواجه شوید .میتوان از مخربها برای پاک کردن منابعی که در برنامه مورد استفاده قرار نمیگیرند استفاده کرد.
معموالً دات نت فریم ورک به صورت اتوماتیک از زباله روب ) (garbage collectionبرای پاک کردن حافظه استفاده میکند و الزم نیست شما به صورت
دستی اشیا را از حافظه پاک کنید .بعضی اوقات زباله روب کارش را به خوبی انجام نمیدهد .به عنوان مثال وقتی یک کانکشن برای پایگاه داده میسازید و یا
یک فایل متنی را برای خواندن باز میکنید .با استفاده از مخربها ،کدی را تعریف میکنید که وقتی اجرا میشود که یک شیء تخریب شده باشد .معموالً شیء
وقتی تخریب میشود که از محدوده خارج شود .دستور نوشتن مخرب کمی با سازنده متفاوت است :
)(~ClassName
{
;code to execute
}
مانند سازندهها ،مخربها باید همنام کالسی باشند که در آن تعریف شدهاند .به این نکته توجه کنید که قبل از نام مخرب عالمت (~) را درج کنید .یک مخرب
نمیتواند دارای سطح دسترسی (مانند )publicباشد .برنامه زیر نحوه فراخوانی سازنده و مخرب را نشان میدهد :
نگران کلماتی مانند protect،Overrideو … نباشید .در درسهای آینده در مورد آنها توضیح میدهیم.
از کلمه کلیدی readonlyبرای فیلدها استفاده میشود و اجازه تغییر مقادیر آنها را نمیدهد .فیلدهای فقط – خواندنی از لحاظ ساختاری بسیار شبیه به ثابتها
هستند با این تفاوت که در هنگام تعریف این نوع فیلدها میتوانید به آنها مقداری اختصاص ندهید .هر چند باید به آنها در داخل سازنده کالس مقادیری اختصاص
دهید .بعد از تخصیص مقدار به یک فیلد فقط خواندنی نمیتوان آن را تغییر داد چون باعث بروز خطا میشود.
در کالس باال دو فیلد فقط – خواندنی تعریف شدهاند .اولین فیلد در هنگام تعریف مقدار گرفته است و دومین فیلد در سازنده کالس.
سطح دسترسی
135
سطح دسترسی مشخص میکند که متدها یک کالس یا اعضای دادهای در چه جای برنامه قابل دسترسی هستند .در این درس میخواهیم به سطح دسترسی
privateو publicنگاهی بیندازیم .سطح دسترسی publicزمانی مورد استفاده قرار میگیرد که شما بخواهید به یک متد یا فیلد در خارج از کالس و حتی
پروژه دسترسی یابید .به عنوان مثال به کد زیر توجه کنید :
در این مثال کالس Testرا به صورت publicتعریف کردهایم .این کار به کالس programاجازه میدهد که از کالس Testنمونه ایجاد کند .سپس یک
عضو دادهای به صورت publicدر داخل کالس Testتعریف میکنیم (خط .)5با تعریف این عضو به صورت publicمیتوانیم آن را در خارج از کالس
Testو در داخل متد )( Mainکالس programمقدار دهی کنیم .اگر از کلمه کلیدی publicاستفاده نکنیم نمیتوانیم در داخل کالس program
نمونهای از کالس Testایجاد کنیم و به اعضای آن دسترسی یابیم و این به نوعی به معنی استفاده از سطح دسترسی privateمیباشد.
همانطور که در مثال باال مشاهده میکنید این بار از کلمه privateدر کالس Testاستفاده کردهایم (خط .)3وقتی که برنامه را کامپایل میکنیم با حطا مواجه
میشویم چون کالس Testدر داخل کالس programو یا هر کالس دیگر قابل دسترسی نیست .به این نکته توجه کنید که با اینکه عضو دادهای کالس
Testبه صورت publicتعریف شده است باز هم نمیتوان به آن در داخل کالس programدسترسی یافت چون کالسی که در داخل آن قرار دارد از نوع
privateاست در نتیجه تمام اعضای مربوطه در خارج از آن غیر قابل دسترسی هستند .نکته دیگر اینکه اگر شما برای یک کالس سطح دسترسی تعریف نکنید
آن کالس دارای سطح دسترسی داخلی ( )internalمیشود به این معنی که فقط کالسهای داخل پروژهای که با آن کار میکنید و میتوانند به آن کالس
136
دسترسی یابند .استفاده از سطح دسترسی internalمعادل استفاده از سطح دسترسی publicاست با این تفاوت که در خارج از پروژه قابل دسترسی نیست.
کدهای زیر دارای تأثیر یکسانی هستند.
class Test
{
}
internal class Test
{
}
اگر یک کالس را به صورت publicو اعضای آن را به صورت privateتعریف کنیم ،آنگاه میتوان یک نمونه از کالس را در داخل کالسهای دیگر ایجاد
کرد ولی اعضای آن قابل دسترسی نیستند .اعضای دادهای privateفقط به وسیله متد داخل کالس Testقابل دسترسی هستند.
سطوح دسترسی دیگری هم در سی شارپ وجود دارد که بعد از مبحث وراثت در درسهای آینده در مورد آنها توضیح خواهیم داد.
کپسوله کردن (تلفیق داده ها با یکدیگر) یا مخفی کردن اطالعات فرایندی است که طی آن اطلالعات حساس یک موضوع از دید کاربر مخفی میشود و فقط
اطالعاتی که الزم باشد برای او نشان داده میشود.
وقتی که یک کالس تعریف میکنیم معموالً تعدادی اعضای دادهای (فیلد) برای ذخیره مقادیر مربوط به شی نیز تعریف میکنیم .برخی از این اعضای دادهای
توسط خود کالس برای عملکرد متدها و برخی دیگر از آنها به عنوان یک متغیر موقت به کار میروند .به این اعضای دادهای ،اعضای مفید نیز می گویند چون
فقط در عملکرد متدها تأثیر دارند و مانند یک داده قابل رویت کالس نیستند .الزم نیست که کاربر به تمام اعضای دادهای یا متدهای کالس دسترسی داشته
باشد .اینکه فیلدها را طوری تعریف کنیم که در خارج از کالس قابل دسترسی باشند بسیار خطرناک است چون ممکن است کاربر رفتار و نتیجه یک متد را تغییر
دهد .به برنامه ساده زیر توجه کنید :
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آمده است :
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 دسترسی
140
دسترسی به مقادیر این فیلدها فقط از طریق propertyهای ارائه شده (خطوط )11-45امکان پذیر است.
وقتی یک خاصیت ایجاد میکنیم ،باید سطح دسترسی آن را 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را بنویسیم .با این کار به برنامه میفهمانیم که ما نیاز به مقدار فیلد داریم.
به این نکته توجه کنید که در بخش getهم می توان تغییراتی بر روی فیلدها اعمال کرد .مثالً فرض کنید که یک فیلد دارید که مقادیر پولی را در خود ذخیره
میکند .شما میتوانید در بخش getنحوه نمایش مقدار موجود در این فیلد را مشخص کنید .مثالً خروجی به صورت سه رقم سه رقم نمایش داده شود .استفاده
از propertyها کد نویسی را انعطاف پذیر میکند مخصوصاً اگر بخواهید یک اعتبارسنجی برای اختصاص یک مقدار به فیلدها یا استخراج یک مقدار از آنها
ایجاد کنید .پس میتوان گفت که :
کاربرد اصلی propertyها ،اعتبار سنجی مقادیری است که کاربر میخواهد به فیلدها اختصاص دهد.
مثالً شما میتوانید یک محدودیت ایجاد کنید که فقط اعداد مثبت به فیلد ( ageسن) اختصاص داده شود .همانطور که در کد ابتدای درس مشاهده میکنید ما
نوع فیلد ageرا intقرار دادهایم .یعنی کاربر میتواند هر رقمی بین اعداد -2147483648تا 2147483647را به این فیلد اختصاص دهد .ولی چون غیر
معقوالنه است و سن ( )ageباید یک عدد مثبت و از لحاظ عقلی عددی از 1تا 100باشد میتوانیم کاربر را با استفاده از بخش setمجبور کنیم که رقمی بین
این دو عدد را به ageاختصاص دهد .میتوانید با تغییر بخش setخاصیت Ageاین کار را انجام دهید :
142
حال اگر کاربر بخواهد یک مقدار منفی به فیلد ageاختصاص دهد مقدار ageصفر خواهد شد .همچنین میتوان یک propertyفقط خواندنی (read-
) onlyایجاد کرد .این propertyفاقد بخش setاست .به عنوان مثال میتوان یک خاصیت Nameفقط خواندنی مانند زیر ایجاد کرد :
در این مورد اگر بخواهید یک مقدار جدید به فیلد nameاختصاص دهید با خطا مواجه میشوید .نکته دیگری که باید به آن توجه کنید این است که شما
میتوانید برای بخش setیا getسطح دسترسی ایجاد کنید .به تکه کد زیر توجه کنید :
خاصیت Nameفقط در خارج از کالس قابل خواندن است اما متدها فقط داخل کالس Personمیتوانند مقادیر جدید بگیرند .یک propertyمیتواند
دارای دو فیلد باشد .به کد زیر توجه کنید :
public FullName
{
} ;get { return firstName + " " + lastName
}
همانطور که در مثال باال مشاهده میکنید یک propertyفقط خواندنی تعریف کردهایم که مقدار برگشتی آن ترکیبی از دو فیلد firstNameو
lastNameاست که به وسیله فاصله از هم جدا شدهاند .سی شارپ همچنین یک راه حل کوتاه برای ایجاد propertyارائه میدهد .در این روش میتوانید
یک propertyبد ون فیلد ایجاد کنید .گاهی اوقات ممکن است که شما اصالً نخواهید اعتبار سنجی انجام دهید .در این صورت بهتر است که آینده نگر باشید و
باز هم به ازای هر فیلد موجود در کالس یک خاصیت تعریف کنید .البته برای کاهش کدنویسی ،میتوانید از نوع خالصه شده propertyها یعنی property
های خودکار استفاده کنید :
این ویژگی فراخوانی خودکار 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هستند .برای درک منظور این درس همه کدهایی که در
هنگام ایجاد کالس به وجود میآیند را حذف کنید و کدهای زیر را وارد کنید :
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برنامهای که قبالً ایجاد کردید بروید .محتویات آنرا پاک کرده و کدهای زیر را مینویسید :
!Hello World
با استفاده از کلمه کلیدی usingهمه محتویات فضای نام MyNamespaceرا که قبالً ایجاد کردیم وارد برنامه جدید میکنیم (خط .)1اگر خط اول کد
باال را حذف کنیم ،برای استفاده از هر چیز باید قبل از Sampleاز کلمه MyNamespaceاستفاده کنیم.
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 MyNamespace1.MyNamespace2
دات نت فریم ورک دارای فضاهای نام تو در تو میباشد .به عنوان مثال System.Data.SqlClientسه فضای تو در تو میباشد .میتوان برای راحتی در
کد نویسی فضاهای نامی تو در تو ،یک فضای نامی مستعاری ایجاد کنید :
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: }
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ایجاد میشود و شما میتوانید کدهایی که الزم دارید را به آن اضافه کنید:
بعد از نوشتن کدها در داخل کالس در قسمت 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به صورت زیر به پروژه اضافه میشود :
;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ارث میبرند .مفهوم اصلی وراثت در مثال زیر نشان داده شده است :
154
{ 25:
26: )public Child(string message) : base(message
27: {
28:
29: }
} 30:
در این مثال دو کالس با نامهای Parentو Childتعریف شده است .در این مثال یک عضو را یکبار با سطح دسترسی ( privateخط )5و یکبار با سطح
دسترسی ( publicخط )7-11تعریف کردهایم .سپس یک متد را برای نمایش پیام تعریف کردهایم .یک سازنده در کالس Parentتعریف شده است که یک
آرگومان از نوع رشته قبول میکند و یک پیغام نمایش میدهد .حال به کالس Childتوجه کنید (خط .)24این کالس تمام متدها و خاصیتهای کالس
Parentرا به ارث برده است .نحوه ارث بری یک کالس به صورت زیر است :
براحتی میتوان با قرار دادن یک کالن ( ) :بعد از نام کالس و سپس نوشتن نام کالسی که از آن ارث بری میشود (کالس پایه) این کار را انجام داد .در داخل
کالس Childهم یک سازنده ساده وجود دارد که یک آرگومان رشتهای قبول میکند .وقتی از وراثت در کالسها استفاده میکنیم ،هم سازنده کالس مشتق و
هم سازنده پیشفرض کالس پایه هر دو اجرا میشوند .سازنده پیشفرض یک سازنده بدون پارامتر است .اگر برای یک کالس سازندهای تعریف نکنیم کامپایلر به
صورت خودکار یک سازنده برای آن ایجاد میکند .اگر هنگام صدا زدن سازنده کالس مشتق بخواهیم سازنده کالس پایه را صدا بزنیم باید از کلمه کلیدی base
استفاده کنیم .کلمه کلیدی baseیک سازنده از کالس پایه را صدا می زند .قبل از این کلمه کلیدی باید عالمت کالن ( ) :را تایپ کنیم.
در مثال باال به وسیله تأمین مقدار پارامتر messageسازنده کالس مشتق و ارسال آن به داخل پرانتز کلمه کلیدی ، baseسازنده معادل آن در کالس پایه
فراخوانی شده و مقدار messageرا به آن ارسال میکند .سازنده کالس Parentهم این مقدار (مقدار )messageرا در یک عضو دادهای (فیلد) private
قرار میدهد .میتوانید کدهایی را به داخل بدنه سازنده Childاضافه کنید تا بعد از سا زنده Parentاجرا شوند .اگر از کلمه کلیدی baseاستفاده نشود به
جای کالس پایه سازنده پیشفرض فراخوانی میشود .اجازه بدهید که اشیایی از کالسهای Parentو Childبسازیم تا نشان دهیم که چگونه کالس Child
متدها و خواص کالس Parentرا به ارث میبرد.
155
Modified message of the parent.
Modified message of the child.
هر دوشی را با استفاده از سازندههای مربوط به خودشان مقدار دهی میکنیم( .خطوط )5-6سپس با استفاده از ارث بری و از طریقشی Childبه اعضاء و
متدهای کالس Parentدسترسی مییابیم .حتی اگر کالس Childاز کالس Parentارث ببرد باز هم اعضای با سطح دسترسی privateدر کالس
Childقابل دسترسی نیستند (خط .)18سطح دسترسی Protectکه در درس آینده توضیح داده خواهد شد به شما اجازه دسترسی به اعضا و متدهای کالس
پایه را میدهد .به نکته دیگر توجه کنید .اگر کالس دیگری بخواهد از کالس Childارث بری کند ،باز هم تمام متدها و خواص کالس Childکه از کالس
Parentبه ارث برده است را به ارث میبرد.
این کالس هیچ چیزی در داخل بدنه ندارد .وقتی کالس GrandChildرا ایجاد میکنید و یک خاصیت از کالس Parentرا فراخوانی میکنید با خطا مواجه
میشوید .چون هیچ سازندهای که یک آرگومان رشتهای قبول کند در داخل بدنه GrandChildتعریف نشده است بنابراین شما میتوانید فقط از سازنده
پیشفرض یا بدون پارامتر استفاده کنید.
وقتی یک کالس ایجاد میکنیم و سازنده GrandChildرا فراخوانی میکنیم ابتدا سازنده کالس Parentفراخوانی میشود و سپس سازنده Childو در
نهایت سازنده GrandChildاجرا میشود .برنامه زیر ترتیب اجرای سازندهها را نشان میدهد .دوباره کالسها را برای خوانایی بیشتر در داخل کدهای جدا قرار
میدهیم.
سطح دسترسی protectاجازه می دهد که اعضای کالس ،فقط در کالسهای مشتق شده از کالس پایه قابل دسترسی باشند .بدیهی است که خود کالس پایه
هم میتواند به این اعضا دسترسی داشته باشد .کالسهایی که از کالس پایه ارث بری نکردهاند نمیتوانند به اعضای با سطح دسترسی protectیابند .در مورد
سطوح دسترسی publicو privateقبالً توضیح دادیم .در جدول زیر نحوه دسترسی به سه سطح ذکر شده نشان داده شده است :
مشاهده میکنید که publicبیشترین سطح دسترسی را داراست .صرف نظر از مکان ،اعضای publicدر هر جا فراخوانی میشوند و قابل دسترسی هستند.
اعضای privateفقط در داخل کالسی که به آن تعلق دارند قابل دسترسی هستند .کد زیر رفتار اعضای دارای این سه سطح دسترسی را نشان میدهد :
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توجه کنید :
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:
159
)(public static void ShowNumber
{
Console.WriteLine(number); //Error: cannot use non-static member
}
اصرار بر این کار باعث بروز خطا میشود .به این نکته نیز توجه کنید که در سی شارپ ،متد )( Mainباید به صورت staticتعریف شود .کامپایلر به
Staticبودن متد )( Mainنیاز دارد تا بتواند برنامه را بدون ساختن نمونه اجرا کند.
کالس Static
یک کالس staticکالسی است که همه اعضای آن staticباشند .یکی از روشهای معمول استفاده از کالس ،staticایجاد یک کتابخانه ریاضی که شامل
تعدادی از توابع و مقادیر است ،میباشد .کالس Mathیکی از این کالسها است که در درسهای آینده در مورد آن توضیح میدهیم .موارد مهمی که در مورد
این کالسها باید بدانید عبارتند از :
160
} 20:
!Hello World
در کد باال یک کالس استاتیک به نام Personدر خطوط 5-11تعریف شده است که دارای یک متد استاتیک با نام () ShowMessageمیباشد
(خطوط .)7-10همانطور که در خط 17مشاهده میکنید برای دسترسی به این متد استاتیک ،بدون اینکه از کالس شیء ایجاد کنیم ،ابتدا نام کالس
سپس عالمت نقطه و در آخر نام متد را مینویسیم.
متدهای مجازی
متدهای مجازی متدهایی از کالس پایه هستند که میتوان به وسیله یک متد از کالس مشتق آنها را overrideکرده و به صورت دلخواه پیاده سازی نمود.
به عنوان مثال شما متد Aرا در کالس Aدارید و کالس Bاز کالس Aارث بری میکند ،در این صورت متد Aدر کالس Bدر دسترس خواهد بود .اما متد
Aدقیق همان متدی است که از کالس Aبه ارث برده شده است .حال اگر بخواهید که این متد رفتار متفاوتی از خود نشان دهد چکار میکنید؟ متد مجازی این
مشکل را برطرف میکند .به تکه کد زیر توجه کنید.
161
متد مجازی با قرار دادن کلمه کلیدی virtualهنگام تعریف متد ،تعریف میشود( .خط )5این کلمه کلیدی نشان میدهد که متد میتواند overrideشود یا
به عبارت دیگر میتواند به صورت دیگر پیاده سازی شود .کالسی که از کالس Parentارث میبرد شامل متدی است که متد مجازی کالس پایه را
overrideیا به صورت دیگری پیاده سازی میکند .با استفاده از کلمه کلیدی overrideمیتوان متد مجازی کالس پایه را به صورت دیگر پیاده سازی کرد.
با استفاده از کلمه کلیدی ( baseخط )17میتوانید متد مجازی را در داخل متد overrideشده فراخوانی کنید.
162
میتوان یک کالس دیگر که از کالس Childارث بری میکند ایجاد کرده و دوباره متد )( ShowMessageرا overrideکرده و آنرا به صورت دیگر
پیاده سازی کنیم .اگر بخواهید متدی را که ایجاد کردهاید به وسیله سایر کالسها overrideنشود کافیست که از کلمه کلیدی sealedبه صورت زیر استفاده
کنید :
حال اگر کالس دیگری از کالس Childارث ببرد نمیتواند متد )( ShowMessageرا overrideکند .به یک مثال دیگر توجه کنید .فرض کنید
میخواهیم متد )( ToStringکالس System.Objectرا overrideکنیم .همانطور که در درس آینده خواهید دید همه کالسها در سی شارپ از کالس
Objectارث میبرند.
John Smith
از آنجاییکه متد )( ToStringکالس System.Objectرا overrideکردهایم ،به جای چاپ نوع شیء پیشفرض ،خروجی ما سفارشی شده و نام و
نام خانوادگی نمایش داده میشود.
همه کالسهای دات نت از کالس آبجکت ( )System.Objectارث میبرند .کالس آبجکت در سی شارپ با کلمه کلیدی objectنشان داده میشود .برای
راحتی در این درس از کلمه آبجکت به جای System.Objectاستفاده میکنیم .در زیر لیست برخی از متدهای معمول در کالس آبجکت آمده است :
163
Static Virtual نوع برگشتی متد
ReferenceEquals
Yes No bool
)(object,object
همه متدهای این کالس معموالً مورد استفاده قرار نمیگیرند .از آنجاییکه همه کالسهای سی شارپ از این کالس ارث میبرند ،آنها نیز دارای این متدها به جز
متدهای Staticمیباشند .وقتی یک کالس ایجاد میکنید ،این کالس به صورت ضمنی از کالس آبجکت ارث میبرد .بنابراین وقتی یک کالس تعریف
میکنید کدها در حقیقت به صورت زیر به وسیله کامپایلر خوانده میشوند :
اینکه چرا همه کالسها در دات نت از objectارث بری میکنند به دلیل امکان استفاده از چندریختی است که در درس آینده درباره آن توضیح میدهیم .به
عنوان مثال یکی از سربارگذاری های متد )( Console.WriteLineقبول نوع آبجکت به عنوان آرگومان است .به همین دلیل است که شما میتوانید تقریباً
هر چیز را به عنوان آرگومان به متد )( Console.WriteLineارسال کنید .برای نشان دادن اینکه هر چیز در سی شارپ یک شیء است به مثال ساده زیر
توجه کنید :
164
} 15:
همانطور که مشاهده میکنید اشیاء double، intو stringهمگی متد )( ToStringرا فراخوانی میکنند که این متد از کالس objectبه ارث برده
شده است.
Boxingو Unboxing
Boxingفرایندی است که طی آن یک نوع مقداری مانند ساختار ( )Structبه یک نوع مرجع مانند یک شیء ( )Objectتبدیل میشودUnboxing .
برعکس ،عمل تبدیل یک نوع مرجع به یک نوع مقداری میباشد .کد زیر فرایند boxingرا نشان میدهد.
در کد باال یک ساختار به نام MyStructایجاد کردهایم و یک خاصیت ( )propertyبرای تست اهداف برای آن در نظر گرفتهایم .در فرایند boxingنوع
مقداری به سادگی با یک متغیر از نوع آبجکت برابر قرار داده میشود .در کد باال refTypeشامل آدرس یک نوع MyStructاست نه آدرس اصلی متغیر
.valueTypeدر زیر نحوه تبدیل refTypeبه نوع مقداری MyStructبه وسیله unboxingنشان داده شده است.
همانطور که مشاهده میکنید با استفاده از تبدیل صریح متغیر نوع مرجع refTypeرا به متغیر نوع مقدار MyStructتبدیل کردهایم.
ترکیب ()Containment
محدود نگه داشتن یا ترکیب فرایندی است که طی آن یک کالس به عنوان یک عضو به کالس دیگر اضافه میشود .به عنوان مثال کالس Personمیتواند
یک فیلد از نوع کالس Nameداشته باشد .به کد زیر توجه کنید :
John Smith
: حال برنامه را به صورت بخش بخش توضیح میدهیم
class Name
{
public string FirstName { get; set; }
public string LastName { get; set; }
166
یک کالس که قرار است به عنوان یک فیلد در کالس دیگر به کار رود را تعریف میکنیم (خط .)17این کالس ،دارای یک سازنده است که نام ( )fو نام
خانوادگی ( )lرا از شخص دریافت میکند .سپس این مقادیر را در خصوصیتهای متناظر با آنها قرار میدهیم (خطوط .)5-12
class Person
{
;private Name myName
این کالس شامل یک فیلد از نوع 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در داخل خود دارد.
کد باال چگونگی دسترسی و مقدار دهی به عضو (Sibling)Personرا نشان داده است .از آنجایی که خصوصیت Siblingاز نوع Personاست پس
میتواند یک شیء Personدر داخل خود داشته باشد .بنابراین میتوان هر تعداد siblingکه میخواهید در داخل شیء person1داشته باشید :
سربارگذاری عملگرها
سربارگذاری عملگرها به شما اجازه می دهد که رفتار عملگرهای سی شارپ را بسته به نوع عملوندهای آنها سفارشی کنید .سربارگذاری عملگرها همچنین به
عملگر اجازه میدهد که یک شیء را به روشی دیگر ترجمه کند .به کد زیر توجه کنید :
خط پررنگ شده در کد باال (خط )18کد قابل قبولی نیست چون ،کامپایلر نمیتواند دو شیء را با هم جمع کند .رفتاری که ما از کد باال انتظار داریم اضافه کردن
مقادیر به خاصیت Numberدو عملوند و سپس ایجاد یک شیء جدید که حاصل جمع دو مقدار در داخل آن قرار بگیرد .سپس این شیء جدید به متغیر sum
تخصیص داده شود.
168
سر بارگذاری عملگرهای دوتایی
برنامه را برای اضافه کردن سربارگذاری یک عملگر دوتایی ( )+که دو عملوند قبول میکند تغییر میدهیم.
Sum = 15
برای سربارگذاری عملگرها به صورت زیر عمل کنید :
همانطور که مشاهده میکنید در سربارگذاری عملگرها از یک متد که هم staticو هم publicباشد استفاده میشود .این متد باید staticباشد چون همه
نمونههای کالس از آن استفاده میکنند و هم باید publicباشد تا بتوان در خارج از کالس از آن استفاده کرد .سپس از کلمه کلیدی operatorو بعد از آن از
میکنیم. استفاده – یا + مانند عملگر یک عالمت
در س ربارگذاری یک عملگر دوتایی به دو عملوند نیاز است ،بنابراین متد دارای دو پارامتر است که این دو عملوند را قبول میکند .در داخل کد یک شیء ایجاد
شده است که نتیجه را در خود نگداری میکند .دو خاصیت Numberبرای دو پارامتر اضافه کرده و حاصل جمع این دو را در خاصیت Numberشی
( resultکه نتیجه را در خود ذخیره میکند) قرار میدهیم (خط .)12و در آخر نتیجه را به فراخوان بازگشت میدهیم (خط .)13شیء resultبه متغیر sum
169
است. شده داده ارجاع
همه عملگرها نمیتوانند سر بارگذاری شوند .مثالً شما نمیتوانید عملگر = +را سربارگذاری کنید .شما میتوانید عملگر +را سربارگذاری کنید که در این صورت
عملگر =+به صورت خودکار سربارگذاری میشود .عملگرهای > یا < باید به صورت جفت سربارگذاری شوند .مثالً نمیتوان عملگر > را به تنهایی سربارگذاری
کنید.
سربارگذاری عملگر یگانی بسیار ساده است .همه کاری که شما باید انجام دهید تهیه یک پارامتر است چون عملگر یگانی 1عملوند قبول میکند .به عنوان مثال،
اجازه دهید که عملگر یگانی ++را سربارگذاری کنیم.
همانطور که می بینید سربارگذاری عملگرهای یگانی شبیه به سربارگذاری عملگرهای دوتایی است .در سربارگذاری عملگرها به نکات زیر توجه کنید :
است. آمده زیر در دارند، را سربارگذاری قابلیت که عملگرهایی لیست
عملگرهای دوتایی :
=< +, -, *, /, %, &, |, ^, <<, >>, ==, !=, >, <, >=,
عملگرهای یگانی
+, -, !, ~, ++, --, true, false
عملگر is
170
عملگر isدر سی شارپ به شما اجازه میدهد که تست کنید که آیا یک شیء میتواند به طور کامل به وسیله تبدیل صریح به شیء دیگری تبدیل شود .عملگر
isبه دو عملوند نیاز دارد و یک مقدار بولی را برمی گرداند .به عنوان مثال ،فرض کنید یک کالس به نام Animelداریم ،سپس یک نمونه از آن ایجاد
میکنیم :
myAnimal is an Animal
رفتار عملگر isرا در این مثال مشاهده کردید .همانطور که میبینید از آن به عنوان شرط در عبارت ifاستفاده شده است .کاربرد آن در مثال باال این است که
چک میکند که آیا شیء myAnimalیک نمونه از Animalاست و چون نتیجه درست است کدهای داخل دستور ifاجرا میشود .این عملگر همچنین
می تواند چک کند که آیا یک شیء خاص در سلسله مراتب وراثت یک نوع خاص است .به این مثال توجه کنید :
!myDog is an Animal
همانطور که در مثال باال میبینید ما یک کالس به نام Dogایجاد کردهایم که از کالس Animalارث میبرد .سپس یک نمونه از این کالس ( )Dogایجاد
میکنیم و سپس با استفاده از عملگر isتست میکنیم که آیا نمونه ایجاد شده جز کالس Animalاست یا یک کالس مشتق شده از کالس Animal
میباشد .از آنجاییکه کالس Dogاز کالس Animalارث میبرد (سگ من یک حیوان است ،).نتیجه عبارت درست ( )trueاست .حال جمله باال را تغییر
دهیم ” :حیوان من یک سگ است” .وقتی جمله برعکس میشود چه اتفاقی می افتد؟
این باعث خطا نمیشود و عبارت فقط نتیجه falseرا بر میگرداند .میتوان از کد باال این را درک کرد که همه حیوانات سگ نیستند ولی همه سگها حیوان
هستند .راه دیگر برای چک کردن نوع یک شیء ( )objectاستفاده از عملگر typeofو متد )( GetTypeکالس System.objectاست.
متد )( GetTypeیک شیء از نوع System.Typeرا بر میگرداند که نشان دهنده نوع شیئی که آن را فراخوانی کرده است ،میباشد .عملگر typeofنام
یک نوع را قبول کرده و شیء System.Typeمتناظر با آن را بر میگرداند.
رابط ها ()Interfaces
رابطها یا اینترفیس ها شبیه به کالسها هستند اما فقط شامل تعاریفی برای متدها و خواص ( )Propertyمیباشند .رابطها را میتوان به عنوان پالگین های
کالسها در نظر گرفت .کالسی که یک رابط خاص را پیاده سازی می کند الزم است که کدهایی برای اجرا توسط اعضا و متدهای آن فراهم کند چون اعضا و
متدهای رابط هیچ کد اجرایی در بدنه خود ندارند .اجازه دهید که نحوه تعریف و استفاده از یک رابط در کالس را توضیح دهیم :
172
{ 17:
18: )(public static void Main
19: {
20: ;)(Sample sample = new Sample
21:
22: ;)"!sample.ShowMessage("Implemented the ISample Interface
23: }
} 24:
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
انجام میدهیم.
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ارسال شده است ،متد مربوط به آن کالس فراخوانی شده و مقادیر فیلدها چاپ میشود .میتوان چند رابط را در کالس
اجرا کرد :
درست است که میتوان از چند رابط در کالس استفاده کرد ولی باید مطمئن شد که کالس میتواند همه اعضای رابطها را تغذیه کند .اگر یک کالس از کالس
پایه ارث ببرد و در عین حال از رابطها هم استفاده کند ،در این صورت باید نام کالس پایه قبل از نام رابطها ذکر شود .به شکل زیر :
همچنین میتوان از عملگر isبرای چک کردن اینکه آیا یک شیء خاص از یک رابط استفاده میکند یا نه استفاده کرد :
)if(sample is ISample
{
;)"!Console.WriteLine("sample implements the ISample Interface
}
نکته دیگر اینکه نمیتوان از یک رابط نمونهای ایجاد کرد چون رابطها دارای سازنده نیستند ،مثالً کد زیر اشتباه است :
interface ISample
{
} ;int Number { get; set
}
175
. کالسی که رابط را پیاده سازی میکند آن را اجرا میکند. خاصیت نوشته شودset وget نباید هیچ کدی در قسمت
: به مثال زیر توجه کنید.رابطها حتی میتوانند رابطهای دیگر را پیاده سازی یا اجرا کنند
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کالسهایی هستند که کالس پایه سایر کالسها هستند .این نوع کالسها میتوانند مانند کالسهای عادی دارای سازنده باشند.
شما نمی توانید از کالسهای انتزاعی نمونه ایجاد کنید چون که هدف اصلی از به کار بردن کالسهای انتزاعی استفاده از آنها به عنوان کالس پایه برای کالسهای
مشتق است .برای تعریف یک کالس انتزاعی از کلمه کلیدی abstractاستفاده میشود .به مثال زیر در مورد استفاده از کالسهای انتزاعی توجه کنید :
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به شما اجازه میدهد که یک کالس را در چندین فایل جداگانه تعریف کنید .به عنوان مثال میتوانید فیلدها ،خاصیتها و
سازندهها را در یک فایل و متدها را در فایل دیگر قرار دهید .برای تعریف این نوع کالسها از کلمه کلیدی partialاستفاده میشود .در مثال زیر نحوه تعریف
یک کالس partialدر دو فایل جدا نشان داده شده است :
178
)(public void DoSomething
{
//Do something here
}
}
در این مثال مشاهده میکنید که برای تعریف کالسها از کلمه کلیدی partialاستفاده شده است .همچنین فایلهای جدا در یک کالس به نام Sampleتعریف
شدهاند .در قسمت اول (فایل اول) یک فیلد و یک propertyو در قسمت دوم (فایل دو) یک متد تعریف شده است .هنگام ارث بری از کالسها یا پیاده سازی
رابطها فقط یک بخش از کالسهای partialبرای ارث بری نیاز است .اگر بخش اول کالس را IInterface1و بخش دوم آن را IInterface2بنامیم در
نهایت کالس اصلی ترکیبی از این دو بخش خواهد بود.
از کالسهای تکه تکه در فرمهای و.یندوزی و وب فرمها برای جدا کردن فایلهای کد از فایلهایی که در سرتاسر طراحی این فرمها به کار میروند
استفاده میشود.
کالس مهر و موم شده ( ،)Sealed Classکالسی است که دیگر کالسها نمیتوانند از آن ارث بری کنند و چون قابلیت ارث بری ندارد نمیتواند مجرد
( )abstractهم باشد .مثال زیر یک کالس مهر و موم شده را نشان میدهد :
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استفاده میشود .مشاهده میکنید که کالسهای مهر و موم شده مانند کالسهای عادی ،دارای فیلد ،خواص،
و متد می باشند .کالس مشتق در مثال باال با خط قرمز نشان داده شده است چون نمیتواند از کالس پایه ارث بری کند .استفاده از این کالسها همانطور که ذکر
شد زمانی مفید است که بخواهید کالسی ایجاد کنید که از دیگر کالسها ارث بری نکند.
چند ریختی به کالسهایی که در یک سلسله مراتب وراثتی مشابه هستند ،اجازه تغییر شکل و سازگاری مناسب میدهد و همچنین به برنامه نویس این امکان را
میدهد که به جای ایجاد برنامههای خاص ،برنامههای کلی و عمومیتری ایجاد کند ..به عنوان مثال ،در دنیای واقعی همه حیوانات غذا میخورند ،اما روشهای
غذا خوردن آنها متفاوت است .در یک برنامه برای مثال ،یک کالس به نام Animalایجاد میکنید .بعد از ایجاد این کالس میتوانید آن را چند ریخت (تبدیل)
به کالس Birdکنید و متد )( Flyرا فراخوانی کنید .به مثالی درباره چند ریختی توجه کنید :
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:
;)(myAnimal.Eat
در مرحله بعد چندریختی روی میدهد .همانطور که در مثال باال مشاهده میکنید شی Dogرا برابر نمونه ایجاد شده از کالس Animalقرار میدهیم (خط
)46و متد )( Eatرا بار دیگر فراخوانی میکنیم .حال با وجود اینکه ما از نمونه کالس Animalاستفاده کردهایم ولی متد )( Eatکالس Dogفراخوانی
میشود .این به دلیل تأثیر چند ریختی است.
سپس دو شیء دیگر ( Birdو )Fishرا برابر نمونه ایجاد شده از کالس Animalقرار میدهیم و متد )( Eatمربوط به هر یک را فراخوانی میکنیم( .خطوط
)51-48به این نکته توجه کنید که وقتی در مثال باال اشیاء را برابر نمونه کالس Animalقرار میدهیم ازعمل Castاستفاده نکردهایم چون این کار ()cast
وقتی که بخواهیم یک شیء از کالس مشتق (مثالً )Dogرا در شیی از کالس پایه ( )Animalذخیره کنیم الزم نیست .همچنین میتوان کالس Animal
را با سازنده هر کالس مشتق دیگر مقدار دهی اولیه کرد :
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:
;)(((Dog)animal1).Run
;)(((Bird)animal2).Fly
;)(((Fish)animal3).Swim
از چند ریختی میتوان در رابطها هم استفاده کرد .به کد زیر توجه کنید :
as عملگر
این عملگر کاری معادل تبدیل صریح انجام. استفاده می شود، برای تبدیل یک کالس به کالس دیگر که در سلسله مراتب وراثتی یکسانی هستندas از عملگر
: نحوه استفاده از این عملگر به صورت زیر است.میدهد و فقط دارای تفاوتی جزئی هستند که در ادامه توضیح میدهیم
myObject as DestinationType;
کدهای زیر با هم برابر. که قرار است شیء به آن تبدیل شود، شیی است که قرار است تبدیل شود و عملگر سمت راست نوع مقصد است،عملگر سمت چپ
: هستند
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به Animalتعریف نشده است .اما چون برای تبدیل صریح متدی را تعریف کردهایم میتوانیم کد را به
شکل زیر تغییر دهیم :
در این درس به شما نشان میدهیم که ،چگونه میتوان آرایهای از کالسها ایجاد کرد .ساخت آرایهای از کالسها تقریباً شبیه به ایجاد آرایهای از انواع دادهای
مانند 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نمایش میدهیم .میتوان از تکنیکهای دیگر که قبالً در
مورد ایجاد آرایه آموختید ،هم استفاده کنید .مثالً ،مثال باال را میتوان به صورت زیر هم نوشت :
در اینجا ،تعداد عناصر آرایه 3 ،peopleمیباشد و کامپایلر هم با شمارش تعداد نمونهها آن را تشخیص میدهد .از این تکنیک ،برای ساخت آرایههای چند
بعدی و دندانه دار هم میتوان استفاده کرد.
ایندکسر ()Indexer
187
مشاهده میکنید میتوان باMain همانطور که در داخل متد. که دارای سه فیلد از نوع رشته است تعریف کردهایمPerson فرض کنید یک کالس به نام
.استفاده از نام فیلدها به آنها دست یافت
using System;
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 اگر بخواهید یک ایندکسر برای کالس.این دقیقاً کاری است که ایندکسرها به شما اجازه انجام آن را میدهند
ولی ایندکسرها از اندیسی که در داخل،) برای دستیابی به فیلدها استفاده میکند.( به این نکته توجه کنید که نمونه از عالمت دات.را به صورت زیر تعییر دهید
.کروشه وجود دارند
firstPerson[0] = "Doe";
firstPerson[1] = "Jane";
firstPerson[2] = "Dallas";
188
تعریف ایندکسر
دستور تعریف ایندکسر به صورت زیر است .به نکاتی در مورد ایندکسرها توجه کنید :
.1ایندکسرها اسم ندارند و به جای اسم باید کلمه کلیدی thisقرار داده شود.
.2پارامترها بین کروشه قرار میگیرند.
.3باید حداقل یک پارامتر داشته باشد.
از آنجاییکه همواره یک عضو نمونه است ،نباید به صورت staticتعریف شود.
تعریف ایندکسر شبیه به تعریف خاصیت است .تفاوت و شباهت این دو به صورت زیر است :
بر خالف خاصیت ،ایندکسر :
در مثال زیر یک Indexerبرای کالس Personتعریف میکنیم .از آنجاییکه این ایندکسر باید فیلدهایی از نوع رشته را مقداردهی کند نوع آن باید string
باشد .در داخل این کالس سه فیلد تعریف شده است و برای دسترسی به آنها از سه اندیس 1 ،0و 2استفاده میکنیم ،در نتیجه داخل کروشه باید از نوع int
استفاده کنیم .در داخل بدنه setو getهم با استفاده از اندیسها میتوانیم مقادیری را به هر یک از فیلدها اختصاص بدهیم یا مقادیر را از آنها بخوانیم :
190
60: }
} 61:
Doe
Jane
Dallas
Jack
Rasel
Chicago
String Interpolation
String interpolationیا الحاق رشتهها ،به شما اجازه میدهد که ،عبارات رشتهای با خوانایی بیشتر ایجاد کنید .در نسخههای قبلی سی شارپ از متد
string.formatبرای الحاق رشتهها و در نسخه 6از ویژگی String interpolationبرای این کار استفاده میشود .دستور استفاده از این ویژگی جدید به
صورت زیر است :
همانطور که در کد باال مشاهده میکنید ،برای الحاق رشتهها قبل از هر رشته یک عالمت $قرار میدهیم .در داخل رشته هم یک یا چند عبارت را که در داخل
آکوالد هستند ،مینویسیم .این عبارت میتواند یک متغیر و یا حاصل یک یا چند متغیر باشد .هر چیز در داخل آکوالد ارزیابی شده و با استفاده از متد
() ToStringبه رشته تبدیل و در داخل رشته قرار داده میشود .اگر بخواهید خود آکوالدها هم پردازش شده و در نتیجه نهایی نمایش داده شوند باید از دو
عالمت آکوالد استفاده کنید ({{ .)}} andبه مثال زیر توجه کنید :
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: }
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: }
برای این کار از کاراکترهای خاص که در درس قالب بندی رشتهها و اعداد آمدهاند میتوان به صورت زیر.می توان نتیجه یک عبارت الحاقی را قالب بندی کرد
: استفاده کرد
193
تعیین طول فیلدها برای تراز بندی مقادیر مفید است ،مخصوصاً اگر بخواهید که آنها را در ستونهای مختلفی نمایش دهید :
این یک مثال ساده بود .فرض کنید که میخواهیم یک رشته یا عدد را تراز کنیم .برای اینکار میتوانی از اعداد مثبت و منفی به صورتی که در مثال زیر آمده
است ،استفاده ک نیم .عدد مثبت باعث اضافه شدن فضای خالی به سمت راست و عدد منفی باعث اضافه شدن فضای خالی به سمت چپ عدد یا رشته میشود.
البته این تعداد فضای خالی به طول رشته یا عدد بستگی دارد .فرض کنید که یک رشته به طول 5کاراکتر داریم و عدد 10را برای اضافه کردن فضای خالی به
سمت راست آن ،به کار میبریم .در اینصورت 10 – 5 = 5کاراکتر به سمت راست آن اضافه میشود .یعنی تعداد فضاهای خالی اضافه شده از تفاضل طولی فیلد
و طول رشته به دست میآید :
در مثال زیر نحوه استفاده از ترازبندی و قالب بندی به طور همزمان نشان داده شده است :
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:
بهترین برنامه نویسان در هنگام برنامه نویسی با خطاها و باگها در برنامهشان مواجه میشوند .درصد زیادی از برنامهها هنگام تست برنامه با خطا مواجه
می شوند .بهتر است برای از بین بردن یا به حداقل رساندن این خطاها ،به کاربر در مورد دالیل به وجود آمدن آنها اخطار داده شود .خوشبختانه سی شارپ برای
این مشکل راه حلی ارائه داده است .دات نت دارای مجموعه بزرگی از کالسهایی است که برای برطرف کردن خطاهای خاص از آنها استفاده میکند .استثناءها در
دات نت راهی برای نشان دادن دلیل وقوع خطا در هنگام اجرای برنامه است.
دات نت دارای مجموعه بزرگی از کالسهای استثناء است که شما میتوانید با استفاده از آنها خطاهایی که در موقعیتهای مختلف روی میدهند را برطرف کنید.
حتی میتوانید یک کالس استثناء شخصی ایجاد کنید .استثناءها توسط برنامه به وجود میآیند و شما الزم است که آنها را اداره کنید .به عنوان مثال در دنیای
کامپیوتر یک عدد صحیح هرگز نمیتواند بر صفر تقسیم شود .اگر بخواهید این کار را انجام دهید (یک عدد صحیح را بر صفر تقسیم کنید) ،با خطا مواجه
میشوید .اگر یک برنامه در سی شارپ با چنین خطایی مواجه شود پیغام خطای ” “DivideByZeroExceptionنشان داده میشود که بدین معنا است که
عدد را نمیتوان بر صفر تقسیم کرد.
باگ ( )Bugاصطالحاً خطا یا کدی است که رفتارهای ناخواستهای در برنامه ایجاد میکند .خطایابی فرایند برطرف کردن باگها است ،بدین معنی که خطاها را از
برنامه پاک کنیم .ویژوال استودیو و ویژوال سی شارپ دارای ابزارهایی برای خطایابی هستند ،که خطاها را یافته و به شما اجازه میدهند آنها را برطرف کنید .در
درسهای آینده خواهید آموخت که چگونه از این ابزارهای کارامد جهت برطرف کردن باگها استفاده کنید .قبل از اینکه برنامه را به پایان برسانید الزم است که
برنامهتان را اشکال زدایی کنید.
استثناءهای اداره نشده ،استثناءهایی هستند که به درستی توسط برنامه اداره نشدهاند و باعث میشوند که برنامه به پایان برسد .در اینجا میخواهیم به شما نشان
دهیم که وقتی یک برنامه در زمان اجرا با یک استثناء مواجه میشود و آن را اداره نمیکند چه اتفاقی می افتد .در آینده خواهید دید که یک استثناء چگونه به
195
صورت بالقوه باعث نابودی جریان و اجرای برنامه شما میشود .از ابتدای آموزش تا کنون برای اجرای برنامهها و نمونه کدها از حالت (Non-Debugبدون
خطایابی) استفاده کردهایم .اجرا کردن یک برنامه بدون خطا در حالت Non-Debugیا Debugدارای تفاوتهای جزئی میباشد .قصد داریم این تفاوت را
برای شما توضیح دهیم .یک برنامه جدید کنسول ایجاد کرده و نام آن را ExceptionTestمیگذاریم.
همانطور که در مثال باال مشاهده میکنید تقسیم یک عدد صحیح بر صفر غیر مجاز است و باعث ایجاد خطای System.DivideByZeroException
میشود.
برنامه را در حالت 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
و بالفاصله پنجره زیر بعد از بستن برنامه نمایش داده میشود :
نمایش پنجره باال به دلیل وجود یک استثناء اداره نشده است ،چون که شما از هیچ کدام از تکنیکهای اداره استثناء استفاده نکردهاید .معموالً جزییات باال برای
کسی که از برنامه شما استفاده میکند الزم نیست.
196
یکی از راههای بهتر برای دیدن اطالعاتی در مورد استثناءهای اداره نشده استفاده از حالت Debugاست .برای استفاده از این حالت برنامه را از مسیر Debug
> Start Debuggingاجرا نمایید .همچنین میتوانید از دکمه F5و یا فلش سبزرنگ واقع در toolbarاستفاده نمایید .به وسیله هر یک از سه حالت باال
برنامه در حالت debugاجرا میشود .در طول اجرای برنامه در این حالت اگر برنامه در قسمتهایی دارای ایراد باشد متوقف شده و خطاهای آن با رنگ زرد
نمایش داده شود و پنجره دستیار استثناء ( )Exception Assistantنمایان گردد.
پنجره دستیار استثناء پنجره ای مفید است که در مورد استثناء و چگونگی برطرف کردنان اطالعاتی در اختیار شما میگذارد .اگر این پنجره مخفی شد به سادگی و
با کلیک بر روی دستوری که دارای خطا است دوباره ظاهر میشود.
میتوان خطاها را با استفاده از دستور try…catchاداره کرد .بدین صورت که کدی را که احتمال میدهید ایجاد خطا کند در داخل بلوک tryقرار میدهید.
بلوک catchهم شامل کدهایی است که وقتی اجرا میشوند که برنامه با خطا مواجه شود .تعریف سادهی این دو بلوک به این صورت است که بلوک tryسعی
میک ند که دستورات را اجرا کند و اگر در بین دستورات خطایی وجود داشته باشد برنامه دستورات مربوط به بخش catchرا اجرا میکند .برنامه زیر نحوه استفاده
از دستور try…catchرا نمایش میدهد :
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: }
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
}
;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استفاده میشود .قبالً یاد گرفتیم که
اگر در بلوک tryیک استثناء رخ دهد همه کدهای موجود در این بلوک نادیده گرفته شده و برنامه به قسمت catchمیرود .کدهای نادیده گرفته شده ممکن
است در برنامه نقش حیاتی داشته باشند.
هدف بلوک finallyهم حفظ نقش این کدها به صورت غیر مستقیم است .کدهایی را که فکر میکنید کدهای پایهای هستند و برای اجرای برنامه الزم هستند
را در داخل بلوک finallyقرار دهید .برنامه زیر نحوه استفاده از این بلوک را نشان میدهد :
try
{
//some code
}
finally
{
//some code
}
از این بلوک معموالً برای بستن یک اتصال پایگاه داده یا بستن یک فایل استفاده میشود.
گاهی اوقات میخو اهید برخی کدها همیشه اجرا شوند خواه استثناء رخ دهد ،خواه رخ ندهد ،در این صورت از بلوک finallyاستفاده میشود .قبالً یاد گرفتیم که
اگر در بلوک tryیک استثناء رخ دهد همه کدهای موجود در این بلوک نادیده گرفته شده و برنامه به قسمت catchمیرود .کدهای نادیده گرفته شده ممکن
است در برنامه نقش حیاتی داشته باشند.
هدف بلوک finallyهم حفظ نقش این کدها به صورت غیر مستقیم است .کدهایی را که فکر میکنید کدهای پایهای هستند و برای اجرای برنامه الزم هستند
را در داخل بلوک finallyقرار دهید .برنامه زیر نحوه استفاده از این بلوک را نشان میدهد :
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:
try
{
//some code
}
finally
{
//some code
}
از این بلوک معموالً برای بستن یک اتصال پایگاه داده یا بستن یک فایل استفاده میشود.
ایجاد استثناء
شما می توانید در هر جای برنامه یک خطای ساختگی ایجاد کنید .همچنین اگر پیغام پیشفرض استثناءها را دوست ندارید میتوانید به دلخواه خودتان یک پیغام
برای نمایش ایجاد کنید .به مثال زیر توجه کنید :
throw error;
که یک رشته را دریافت و آن را به عنوان پیغامException همچنین می توان یک پیغام خطای سفارشی را به وسیله یکی دیگر از سربارگذاری های کالس
. نمایش داد،خطا نمایش میدهد
ایجاد استثناء بیشتر در مواقعی به کار میرود که یک کد در حالت. ذخیره میشودMessage در این حالت پیغام خطای پیشفرض تغییر کرده و در خاصیت
.عادی خطا ندارد ولی شما میخواهید در هر صورت به عنوان یک خطا در نظر گرفته شود
Exception خواص
203
کالس پایه System.Exceptionکالسی است که سایر کالسهای استثناء از آن ارث بری میکنند .بنابراین خواص این کالس در دسترس سایر کالسهای
استثناء میباشد .در جدول زیر برخی از خواص برجسته کالس Exceptionکه در همه کالسهای استثناء وجود دارند آمده است :
توضیحات خواص
خاصیت Message
این خاصیت به شما اجازه میدهد که در مورد استثناء به وجود آمده توضیحاتی ارائه دهید .به عنوان مثال به کد زیر توجه کنید :
;int x = 1
;int y = 0
;int z
try
{
;z = x / y
}
)catch (Exception ex
{
;)Console.WriteLine(ex.Message
}
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);
}
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: }
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هم خطا رخ داده است .به کد زیر دقت کنید:
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کد زیر را وارد کنید :
208
اشکال زدایی فرایندی است که طی آن خطاها و باگ های برنامه شما تشخیص داده می شود .اگر خطا های دستوری برنامه تان را با استفاده از پنجره Error
Listبرطرف کرده اید ،مرحله بعد پیدا کردن خطاهای منطقی و استثناءها در هنگام اجرای برنامه است .ویژوال استودیو و ویژوال سی شارپ دارای ابزارهای
هستند. زدایی اشکال برای کارامدی
با استفاده از این ابزارها می توانید برنامه را در نقاط خاصی (دلخواه) متوقف کرده و مقادیر هر یک از متغیرهایی را که توسط برنامه مورد استفاده قرار می گیرند را
مشاهده نمایید .این کار را می ت وان به صورت گام به گام و خط به خط انجام داد .می توانید استثناء را چک کرده و از طریق راهنمای ویژوال استودیو که در
درسهای آینده توضیح می دهیم مشکالت مربوط را برطرف کرد.
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
}
}
}
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آن را فعال یا غیر فعال کرد.
using System;
namespace SteppingThroughCode
{
public class MyClass
{
public static void ShowMessage()
{
Console.WriteLine("Hello World!");
Console.WriteLine("Have a nice day!");
}
}
MyClass.ShowMessage();
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
{
215
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
firstName = "Mike";
lastName = "Welsh";
age = 30;
secondPerson.FirstName = firstName;
secondPerson.LastName = lastName;
secondPerson.Age = 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یک مقدار ثابت را با مقدار یک متغیر که در برنامه وجود دارد جمع کرده و نتیجه را مشاهده
کنید.
قبالً یاد گرفتیم که آرایهها به ما اجازه ذخیره چندین مقدار از یک نوع را میدهند .آرایهها از کالس مجرد System.Arrayارث بری میکنند که این کالس
دارای خواص و متدهایی برای کار با دادههای سادهای مانند طول آرایه میباشد .آرایههای ساده در سی شارپ دارای طول ثابتی هستند که یک بار تعریف و
دهید. کاهش یا افزایش را خاص آرایه یک طول نمیتوانید شما و میشوند مقداردهی
دات نت گزینه بهتری برای جایگزین کردن با آرایهها پیشنهاد میدهد و بیشتر آنها کالسها و رابطهایی هستند که ،در فضای نام System.Collections
قرار دارند .به عنوان مثال کالس ArrayListرفتاری شبیه به یک آرایه معمولی دارد با این تفاوت که به شما اجازه میدهد که طول آن را به صورت پویا تغییر
داده یا یک عنصر را در طول اجرای برنامه به آن اضافه کرده و یا از آن حذف نمایید .در درس بعد پی میبرید که چگونه یک کالس که شامل مجموعهای از
اشیاء است را به وسیله اجرا کردن و یا ارث بری از رابطها و متدها ایجاد کنیم.
کالس ArrayList
کالس ArrayListبه شما اجازه ذخیره مقادیر انواع دادهای مختلف ،و توانایی حذف و اضافه عناصر آرایه در هر لحظه را میدهد .در مثال زیر به سادگی کاربرد
کالس ArrayListآمده است.
;using System
;using System.Collections
;)"myArray.Add("John
;)myArray.Add(5
;)myArray.Add(true
;)myArray.Add(3.65
;)'myArray.Add('R
John
5
true
3.65
R
برای استفاده از این کالس ابتدا باید در قسمت فضاهای نامی ،فضای نام System.Collectionsرا وارد کنیم (خط .)2همانطور که در مثال مشاهده
میکنید یک نمونه از کالس ArrayListایجاد میکنیم .برای اضافه کردن یک عنصر به آرایه باید از متد () Addاستفاده کنیم .از آنجاییکه شی ایجاد شده از
کالس ArrayListآرگومانی از نوع objectقبول میکند بنابراین میتوان مقادیری از هر نوع دادهای به آن ارسال کرد چون هر چیز در سی شارپ از
objectارث بری میکند.
حال برای نمایش توانایی این کالس در نگهداری انواع دادهای مختلف پنج مقدار از پنج نوع مختلف داده را به آن اضافه میکنیم .سپس همه مقادیر را با استفاده
از دستور foreachمیخوانیم .چون کالس ArrayListدارای انواع دادهای مختلفی است نمیتوانیم از یک نوع دادهای خاص برای خواندن مقادیر استفاده
کنیم .لذا برای این کار باید از نوع objectکه میتواند هر نوع دادهای در خود ذخیره کند استفاده نمود .در داخل حلقه از متد () ToStringبرای نشان دادن
مقادیر استفاده کردهایم .به این نکته توجه کنید که برای دسترسی به هر عنصر میتوانید از طریق اندیس آن قدام نمایید .کد زیر نحوه استفاده از حلقه forبرای
دسترسی به هر یک از اعضا را نشان میدهد.
به خاصیت Countدر کد باال توجه کنید .این خاصیت درست شبیه به خاصیت Lengthآرایه معمولی است و کار آن شمارش تعداد عناصرشی ArrayList
میباشد ..در کد باال همانطور که نشان داده شده است میتوان به هر یک از عناصر با استفاده از اندیسشان دست یافت .نکته دیگر این است که شما میتوانید به
کالس ArrayListیک ظرفیت ابتدایی بدهید .به عنوان مثال شما میتوانید با استفاده از یک سازنده سربارگذاری شده نشان دهید که یکشی ArrayList
میتواند دارای 5عنصر باشد.
کد باال 5مکان خالی به وجود میآورد و شما میتوانید با استفاده از متد () Addیکی دیگر به آنها اضافه کنید .اگر همه مکانها به وسیله مقادیر پر شوند میتوان
سایزشی ایجاد شده از کالس ArrayListرا با استفاده از تغییر خاصیت Capacityآن تغییر داد .یکی دیگر از نسخههای سازنده کالس ArrayList
شیئی که رابط Icollectionرا اجرا میکند را قبول میکند System.Array .مثالی از این شیء است .بنابراین شما یک آرایه را به سازنده ارسال میکنید و
مقادیر آن آرایه در شیء ArrayListکپی میشوند.
221
object[] array = {"John", 5, true, 3.65, 'R' };
یک شیء که مطابق مقدار یک عنصر در آرایه است را قبولRemove)( متد. عناصر را پاک کردArrayList کالسRemove)( میتوان با استفاده از متد
اگر عنصری را که مکانی غیر از مکان آخر آرایه باشد حذف کنید بقیه عناصر بعد از آن. این متد به محض رسیدن به مقدار مورد نظر آن را حذف میکند.میکند
در این صورت جای خالی این، را حذف میکنید3 عنصر است و شما عنصر5 عنصر مکان خود را تنظیم میکنند به این معنی که فرض کنید آرایهای دارای
: به تکه کد زیر توجه کنید. پر میشود5 توسط عنصر4 و جای عنصر4 عنصر توسط عنصر
using System;
using System.Collections;
myArray.Add("John");
myArray.Add(5);
myArray.Add(true);
myArray.Add(3.65);
myArray.Add('R');
myArray[0] = John
myArray[1] = 5
myArray[2] = True
myArray[3] = 3.65
myArray[4] = R
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اضافه کند.
;)myArray.Add(1
;)myArray.Add(2
;)myArray.AddRange(numbers
1
2
3
4
5
متد () RemoveRangeکامالً با متد () AddRangeمتفاوت است .این متد دو پارامتر قبول میکند ،اندیس عنصری که فرایند حذف از آن شروع میشود و
تعداد عناصری که میخواهیم حذف کنیم .به عنوان مثال اگر بخواهید عناصر 2تا 6را حذف کنید باید تکه کد زیر را بنویسید :
;)myArray.RemoveRange(2, 5
جستجوی مقادیر
با استفاده از متد () Containsمی توان چک کرد که آیا یک مقدار خاص در داخل آرایه وجود دارد یا خیر .این متد یک آرگومان از نوع شیء را قبول کرده و اگر
یک مقدار را در داخل لیست عناصر پیدا کند trueرا بر میگرداند ،از متدهای () IndexOfو () LastIndexOfبرای تشخیص اندیس یک مقدار خاص
استفاده میشود.
متد () IndexOfاندیس اولین محل وقوع یک مقدار خاص را بر میگرداند.
متد () LastIndexOfاندیس آخرین محل وقوع یک مقدار خاص را بر میگرداند.
223
هر دو متد ،در صورتیکه مقدار مورد نظر را پیدا نکنند مقدار -1را بر میگردانند.
متد () BinarySearchهم میتوان برای جستجوی یک مقدار استفاده نمود .البته این متد برای جستجو یک عنصر در داخل تعداد زیادی از عناصر مناسب
است.
با استفاده از متد Sortمیتوان مقادیر یک آرایه را مرتب نمود .اعداد از بزرگ به کوچک و رشته بر اساس حروف الفبا مرتب میشوند .اگر از این متد استفاده
کنید همه اجزا با هم مقایسه میشوند .به عنوان مثال نمیتوان یک رشته و یک عدد از نوع intرا در داخل ArrayListقرار داد و آنها را با متد () Sortمرتب
نمود .در درس آینده یاد خواهید گرفت که چگونه از یک مقایسه گر سفارشی برای مرتب کردن عناصر استفاده نمود.
ایجاد یک کلکسیون
سی شارپ به شما توانایی ایجاد کلکسیون ی از کالس ها را می دهد .به عنوان مثال می توان کالسی ایجاد کرد که شامل چندین نمونه از کالس های دیگر
باشد .این کالس خصوصیاتی مانند حذف و اضافه نمونه ها از کلکسیون را دارا می باشد .به مثال زیر توجه کنید :
;using System.Collections
در مثال باال دو کالس تعریف شده است .اولین کالس ،کالس Animalاست که یک عنصر از کلکسیون کالسمان است .دومین کالس ،کلکسیون کالسمان
است ( )Animalsکه شامل مجموعه ای از اشیاء کالس Animalمی باشد .برای استفاده بهتر از کاربرد کلکسیون ها ،کالسمان از کالس
224
کالس. را قسمت تعریف فضاهای نامی وارد کنیدSystem.Collections به این نکته توجه کنید که فضای نام. ارث بری می کندCollectionBase
برای حذف یا. می باشد، که مجموعه ای از اشیاء را در خود جای می دهدList و خاصیتRemove)( وAdd)( دارای متدهایی مانندCollectionBase
بنابراین. یک شیء قبول می کنند نه یک کالسList متدهای خاصیت. و متد مربوطه استفاده نمودList اضافه کردن اشیاء به سادگی می توان از خاصیت
. نتیجه را تبدیل و سپس آن را به کاربر برگشت دهیمcast وقتی که یک ایندکسر تعریف می کنیم الزم است که ابتدا با استفاده از عمل
شی قبول می کند الزم است که،List از آنجاییکه خاصیت.با استفاده از کد باال می توانیم به هر یک از اشیاء کلکسیون بوسیله اندیس مکانشان دسترسی یابیم
: به برنامه زیر توجه کنید. تبدیل کنیمAnimal آنها را به اشیاءcast با استفاده از عمل
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هم می
توان انجام داد:
}
در درس آینده با genericها آشنا می شوید ،که راهی آسان برای ایجاد کلکسیونی از هر نوع ،بدون ایجاد کالسی که از کالس پایه CollectionBase
ارث بری کند ،می باشد.
ساخت دیکشنری
می توان یک کالس ایجاد کرد که از کالس DictionaryBaseمشتق شود .با این روش شما می توانید به هر عنصر با استفاده از یک کلید (( )keyکه
معموال از نوع رشته است) دسترسی یابید .این کلیدها دارای یک مقدار ( )valueوابسته به خود هستند .برای فراخوانی هر یک از آیتم های دیکشنری از کلید آن
استفاده می کنیم نه از اندیس آن.
به کد زیر توجه کنید :
;using System.Collections
Animals سپس یک کالس به نام.)3-15 تعریف کرده ایم که قرار است در کالس دیکشنری مورد استفاده قرار بگیرد(خطوطAnimal یک کالس به نام
حال می توان متدهایی. ارث بری می کندDictionaryBase است)که از کالسAnimals و دیگریAnimal ایجاد می کنیم (نام یکی از کالس ها
که می خواهیم به دیکشنری اضافه کنیمAnimal به یک کلید از نوع رشته و یک شیAdd)( متد.برای حذف و اضافه ورودی های دیکشنری تعریف کرد
فقط بهRemove)( متد. برای اضافه کردن یک ورودی به دیکشنری استفاده می کنیمDictionaryBase کالسDictionary از خاصیت.احتیاج دارد
ما یک ایندکسر تعریف کرده. برای حذف آیتم ها استفاده می کنیمDictionary در این متد هم از خاصیت.کلید شی ایی که می خواهیم حذف کنیم نیاز دارد
. اجازه بدهید برای نشان دان توانایی های کالس دیکشنری مان یک کالس ایجاد کنیم. یک کلید از نوع رشته قبول می کند، int ایم که به جای یک مقدار
using System;
animalDictionary.Remove("Animal3");
Console.WriteLine("nFrank was removed from the dictionary.");
Hashtable
از Hashtableزمانی استفاده می شود که بخواهید اطالعات را بر اساس کلید /مقدار ذخیره کنید .به عنوان مثال نام دانش آموز و نمره او در
امتحان Hashtable.به شما اجازه تلفیق متن و عدد را می دهد .یک پروژه جدید ایجاد کنید .با زدن دکمه F7به محیط کدنویسی رفته و در باالی کدها و در
قسمت تعریف فضای نام ،فضای نام زیر را وارد کنید :
;using System.Collections
Hashtableدر این فضای نام قرار دارد .کد زیر را هم در داخل متد Mainوارد کنید.
کد باال یک شئ به نام 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
قبل از اجرای کد به حلقه foreachتوجه کنید .در داخل پرانتزها از دستور زیر استفاده کرده ایم :
DictionaryEntry child
کد باال یک متغیر به نام childرا که نوع آن یک DictionaryEntryمی باشد ایجاد می کند .سی شارپ با استفاده از یک شی از این نوع در هنگام کار با
،Hashtableمقادیر و کلید ها را برگشت می دهد .در مثال فوق مقادیر و کلید ها را در داخل کنترل listboxنشان می دهیم.
بعد از نوشتن نام متغیرمان (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
همانطور که می بینید با استفاده از نام کلید ،نه مقدار ،یک آیتم را می توان حذف نمود.
در درسهای قبلی دیدید که چگونه با استفاده از حلقه foreachعناصر یک آرایه را پیمایش میکردیم .در این درس میخواهیم کمی دقیقتر به قضیه آرایهها
نگاه کنیم و ببینیم که چرا از آنها میتوانند توسط این حلقه مورد پردازش قرار گیرند .همچنین یاد میگیرید که چطور از این قابلیت در کالسهایی که خودتان
تعریف کردهاید استفاده کنید.
وقتی که از حلقه foreachدر یک آرایه استفاده میکنید ،این حلقه تک تک اعضای آرایه را به شما ارائه داده و اجازه میدهد که مقادیر آنها را مشاهده کنید .به
عنوان مثال در زیر یک آرایه با چهار عنصر تعریف شده است و میخواهیم با استفاده از حلقه foreachمقادیر عناصر آن را چاپ کنیم :
رابط IEnumerator
یک شمارنده ( )enumeratorرابط IEnumeratorرا پیاده سازی میکند که دارای دو متد () )( Reset،MoveNextو یک خاصیت به نام Current
میباشد .خاصیت Currentعنصر جاری یک مجموعه را بر میگرداند .این خاصیت یک خاصیت فقط خواندنی ( )read-onlyاست و چیزی که برمی گرداند
از نوع objectمیباشد .متد () MoveNextمتدی است که ،مکان شمارنده را از یک آیتم در مجموعه به آیتمی دیگر منتقل میکند .این متد یک مقدار بولی
را بر میگرداند که نشان میدهد که آیا مکان دیگری برای خواندن در دسترس است یا به انتهای مجموعه رسیده است .اگر مکان جدیدی وجود داشته باشد مقدار
trueو در غیر اینصورت مقدار falseرا بر میگرداند .مکان اولیه شمارنده قبل از اولین آیتم مجموعه است ،بنابراین () MoveNextباید قبل از اولین
دسترسی خاصیت Currentفراخوانی شود .متد () Resetمتدی برای برگرداندن شمارنده به موقعیت اولیه خود قبل از جابجایی است .به تعبیری دیگر ،موقعیت
اولیه مجموعه را برمی گرداند .با در اختیار داشتن یک شمارنده ( )enumeratorشما قادر خواهید بود که حلقه foreachرا شبیه سازی کرده و عناصر یک
مجموعه را با استفاده ازمتد () MoveNextو خاصیت Currentپیمایش کنید .برای درک بهتر عملکرد دو متد و خاصیت مذکور به شکل و کد زیر توجه کنید
:
;))(Console.WriteLine(i.ToString
10
همانطور که در کد باال مشاهده میکنید متد () GetEnumeratorآرایه numbersرا به نوع شمارش پذیر تبدیل میکند ،سپس با فراخوانی متد
() MoveNextعدد 10که اولین عضو آرایه است به عنوان عنصر جاری ( )Currentبر گردانده میشود .حال فرض کنید که شما میخواهید عدد 12را
چاپ کنید ،برای این کار باید متد () MoveNextرا سه با فراخوانی کنید :
;)(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;
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;
این. را پیاده سازی میکند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];
}
پارامتری از نوعGetEnumerator)( این کالس در متد، را پیاده سازی میکندIEnumerable اکنون ما کالسی دیگر ایجاد میکنیم که رابط
: کالس باال برمی گرداند مطابق شکل زیر
: به کد زیر توجه کنید. برای پیمایش اعضای آن استفاده کنیم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میخواند.
)foreach(int n in numbers
{
;)Console.WriteLine(n
}
برای درک بهتر کاربرد تکرارکنندهها ( ،)iteratorsاجازه دهید که حلقه foreachکد باال را به فراخوانی متد () GetEnumeratorآرایه ترجمه کنیم :
همانطور که مشاهده میکنید ما ابتدا یک پیمایشگر آرایه را با استفاده از متد () GetEnumeratorکه یک رابط IEnumeratorرا بر میگرداند به
دست میآوریم .سپس از این پیمایشگر در حلقه whileاستفاده کرده و متد () MoveNextرا فراخوانی میکنیم .متد () MoveNextاولین عنصر یک
کلکسیون مانند آرایه را بر میگرداند و اگر عملیات به دست آوردن اولین عنصر موفقیت آمیز باشد مقدار trueرا بر میگرداند .در فراخوانی بعدی دومین
عنصر آرایه را بر میگرداند و این کار را تا آخرین عنصر آرایه انجام میدهد و وقتی که به پایان عناصر رسید مقدار falseرا برگشت میدهد .مقدار برگشت
داده شده یک عنصر به وسیله خاصیت IEnumerator.Currentقابل دسترسی است .برای استفاده از iteratorنیاز به دستور yield return
داریم .این دستور ( )yieldبا دستور returnمتفاوت است .یکی از تفاوتهای مشهود این دو ،استفاده از کلمه کلیدی yieldقبل از کلمه کلیدی
returnمیباشد yield .یک عنصر مجموعه را برمی گرداند و موقعیت مکان نما را به عنصر بعدی هدایت میکند .به کد زیر توجه کنید :
234
Message 1
Message 2
Message 3
مقدار جلوی. میباشدGetEnumerator)( شامل تعریفی برای یک متد، را بر میگرداند کهIEnumerable یک شئGetMessages)( متد
در حلقهGetMessages)( در فراخوانی بعدی متد. قرار میگیرد و چاپ میشودforeach دستورmessage در متغیرyield return اولین دستور
برای توقف مقادیر برگشتی. ادامه مییابدyield return چاپ میشود و این کار تا آخرین دستورyield return مقدار جلوی دومین دستورforeach
: به صورت زیر استفاده کردyield break از متد میتوان از دستور
اجازه دهید با ذکر یک مثال نحوه استفاده از. شما را با نحوه ایجاد یک پیمایشگر سفارشی آشنا میکنیم،حال که با نحوه عملکرد پیمایشگرها آشنا شدید
میخواهیم یک پیمایشگر ایجاد کنیم که با استفاده از. است توضیح دهیم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شروع میشوند را
برگرداند :
همانطور که در کد باال مشاهده میکنید برای تشخیص اینکه چه نامی با حرف Mشروع شده است از متد () StartsWithمربوط به کالس
System.Stringاستفاده کردهایم .اگر نام با حرف Mشروع شده باشد ،دستور yieldآن را بر میگرداند ،در غیر اینصورت ،از آن رد شده و به نام
بعدی در innerListرا مورد بررسی قرار میدهد .با دستکاری متد () ،GetEnumeratorهنگام استفاده از حلقه foreachدر یک نمونه از کالس
،Namesمیتوانیم فقط نامهایی را که با حرف Mشروع میشوند را به دست آوریم .اگر چه میتوانید از تکنیک باال استفاده کرده و متد
() GetEnumeratorتغییر دهید ولی بهتر است از یک متد جدا برای به دست آوردن نامهایی که با یک حرف خاص شروع میشوند استفاده کنید :
پیمایشگر باال نسبت به پیمایشگر قبلی منعطفتر بوده و شما میتوانید با استفاده از آن نامهایی که با یک حرف یا زیررشته خاص شروع شدهاند را پیدا کنید.
به این نکته توجه کنید که در پیمایشگر باال از IEnumerableبه جای IEnumeratorاستفاده کردهایم IEnumerable .دارای متد
() GetEnumeratorاست .هنگام فراخوانی این پیمایشگر الزم است که حلقه foreachخطوط 33-36را به صورت زیر تغییر دهید :
جنریک ها ()Generics
جنریک ها کالسها ،متدها یا رابطهایی هستند که بسته به نوع دادهای که به آنها اختصاص داده میشود رفتارشان را سازگار میکنند .به عنوان مثال میتوان
یک متد جنریک تعریف کرد که هر نوع دادهای را قبول کند .همچنین میتوان یک متد ایجاد کرد که بسته به نوع دریافتی ،مقادیری از انواع دادهای مانند ،int
doubleیا stringرا نشان دهد .اگر از جنریک ها استفاده نکنید باید چند متد و یا حتی چندین متد سربارگذاری شده برای نمایش هر نوع ممکن ایجاد کنید.
با استفاده از جنریک ها میتوان متد جنریکی ایجاد کرد که هر نوع دادهای را قبول کند.
متدهای جنریک را در درسهای آینده توضیح خواهیم داد .حتماً این سؤال را از خودتان میپرسید که چرا نباید از نوع آبجکت که هر نوع دادهای را قبول میکند
استفاده کنیم؟ در آینده مشاهده میکنید که با استفاده از جنریک ها نیاز به عمل ( castتبدیل صریح) ندارید .درباره جنریک ها در درسهای بعد مطالب بیشتری
توضیح میدهیم.
متدهای جنریک
اگر بخواهید چندین متد با عملکرد مشابه ایجاد کنید و فقط تفاوت آنها در نوع دادهای باشد که قبول میکنند (مثالً یکی نوع intو دیگری نوع doubleرا
قبول کند) می توان از متدهای جنریک برای صرفه جویی در کدنویسی استفاده کرد .ساختار عمومی یک متد جنریک به شکل زیر است :
237
;type someVariable
}
مشاهده می کنید که بعد از نام متد یک نوع در داخل دو عالمت بزرگتر و کوچکتر آمده است ( > ) <typeکه همه انواع در سی شارپ میتوانند جایگزین آن
شوند .برنامه زیر مثالی از نحوه استفاده از متد جنریک میباشد :
;using System
;)Show(intValue
;)Show(doubleValue
;)Show(stringValue
;)Show(boolValue
}
}
5
10.54
Hello
true
یک متد جنریک ایجاد کردهایم که هر نوع دادهای راقبول کرده و مقادیر آنها را نمایش میدهد (خطوط .)5-8سپس دادههای مختلفی با وظایف یکسان به آن
ارسال میکنیم .متد نیز نوع Xرا بسته به نوع دادهای که به عنوان آرگومان ارسال شده است تغییر میدهد .به عنوان مثال وقتی یک داده از نوع intارسال
میکنیم ،همه مکانهایی که Xدر آنها وجود دارد به intتبدیل میشوند و متد به صورت زیر در میآید :
همچنین هنگام فراخوانی متد جنریک صریحاً میتوانید نوعی را که به وسیله آن مورد استفاده قرار میگیرد ذکر کنید (البته الزم نیست) .به عنوان مثال
فراخوانیهای متد باال را میتوان به صورت زیر هم نوشت :
;)Show<int>(intValue
;)Show<double>(doubleValue
;)Show<string>(stringValue
238
;)Show<bool>(boolValue
به یک نکته در مورد استفاده از متدهای جنریک توجه کنید و آن این است که ،قبل از دانت نت ،4.5انجام محاسبات به وسیله متدهای جنریک امکان پذیر نبود.
یعنی شما نمی توانستید که دو عدد را با هم جمع کنید:
ولی در نسخه 4.5دات نت این مشکل با استفاده از کلمه کلیدی dynamicبه صورت زیر قابل حل است :
;)Console.WriteLine((dynamic)val1 + (dynamic)val2
شما می توانید چندین نوع خاص را برای متد جنریک ارسال کنید ،برای این کار هر نوع را به وسیله کاما از دیگری جدا کنید.
به مثال زیر که در آن دو مقدار مختلف به متد ارسال شده است توجه کنید :
;)Show(5, true
// OR
مشاهده میکنید که Xبا نوع intو Yبا نوع boolجایگزین میشود .این نکته را نیز یادآور شویم که شما میتوانید دو آرگومان هم نوع را هم به متد ارسال
کنید :
;)Show(5, 10
// OR
کالس جنریک
تعریف یک کالس جنریک بسیار شبیه به تعریف یک متد جنریک است .کالس جنریک دارای یک عالمت بزرگتر و کوچکتر و یک نوع پارامتر خاص میباشد.
برنامه زیر مثالی از یک کالس جنریک میباشد :
;using System
239
public class GenericClass<T>
{
private T someField;
public T SomeProperty
{
get { return someField; }
set { someField = value; }
}
}
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>( یک نوع هم برای آن در نظر بگیرید، وقتی یک نمونه از کالس جنریک تان ایجاد میکنید. جایگزین میشوند،انواعی که مد نظر شما است
.متدهای جنریک میتوانید چندین نوع پارامتر به کالسهای جنریک اختصاص دهید
. از آنها نمونه جدید ایجاد کنید، نمیتوانید مانند مثال زیر، از چه نوعی هستندT3 وT2 ،T1 چون نمیدانید
240
{
;)(someField1 = new T1
;)(someField2 = new T2
;)(someField3 = new T3
}
کالسهای غیر جنریک میتوانند از کال سهای جنریک ارث بری کنند ،اما باید یک نوع برای پارامترکالس پایه جنریک تعریف کنید.
}
یک کالس جنریک هم میتواند از یک کالس غیر جنریک ارث بری کند.
کد جنریک باید برای هر نوع دادهای کار کند .یک عمل محاسباتی مانند عمل جمع که بر روی انواع صحیح انجام میشود ،نمیتواند در صورتی که عملگر +
سربارگذاری نشده باشد ،بر روی سایر اشیاء عمل کند .در نتیجه شما باید برای یک متد یا کالس جنریک محدودیت نوع ( )Type Constraintsدر نظر
بگیرید که فقط انواع خاصی در این لیست محدودیت قرار بگیرند.
برای ایجاد این محدودیت ابتدا کلمه کلیدی whereسپس نام نوع پارامتر ،یک کالن ( ):و در آخر اگر پارامتر Tدارای لیستی از محدودیتها است باید آنها را به
وسیله کاما از هم جدا کنیم .کد باال دارای یک محدودیت است و آن نوع intمیباشد ،بدین معنی که کالس جنریک ما فقط میتواند این نوع را قبول کند .اگر
بخواهید چندین محدودیت ایجاد کنید باید به صورت زیر عمل نمایید :
پارامتر Tدر کد باال فقط نوع intو stringرا قبول میکند .میتوانید از کلمه کلیدی structاستفاده کنید بدین معنی که ،کالس جنریک فقط انواع مقداری
را قبول کند و یا کلمه کلیدی Classرا به کار برید که کالس جنریک فقط انواع مرجع را پذیرا باشد .همچنین میتوان از کلمه کلیدی interfaceهم استفاده
کرد ،که در نتیجه کالس میتواند اشیایی که رابطها را پیاده سازی میکنند را ،قبول کند.
همچنین می توان نام یک کالس را به عنوان محدودیت نوع تعیین کرد .بدین معنی که نوع را محدود به آن کالس و کالسهای مشتق شده از آن کند .میتوان
تعیین کرد که کالس جنریک فقط کالسهایی که دارای یک سازنده بدون پارامتر هستند را قبول کند .برای ایجاد این محدودیت باید از () newبه صورت زیر
استفاده شود :
در این مورد اگر چندین محدودیت وجود داشته باشد باید () newرا در آخر آنها قرار دهیم .اگر کالس دارای چندین پارامتر باشد و شما بخواهید برای هر یک از
آنها محدودیتهای مختلفی ایجاد کند میتوانید دستور whereرا به صورت زیر اعمال نمایید :
اگر یک کالس جنریک از یک کالس دیگر ارث بری کند باید نام آن کالس را قبل از محدودیتها ذکر نمایید.
میتوان یک کلکسیون عمومی تعریف کرد که شامل هر نوع دادهای باشد .برای ایجاد یک کلکسیون عمومی از کالس > List<Tمربوط به فضای نامی
System.Collections.Genericsاستفاده میشود List<T> .میتواند مجموعهای از اشیاء نوع Tباشد .در نتیجه > List<intمجموعهای از مقادیر
صحیح است.
کالس > List<Tدارای متدهای )( RemoveAt() ،Remove() ،AddRangeو دیگر متدهایی است که در کالس کلکسیونمان در درس قبلی از آنها
استفاده کردیم.
242
using System;
using System.Collections.Generic;
animals.Add(new Animal("Dog"));
animals.Add(new Animal("Cat"));
animals.Add(new Animal("Rat"));
Dog
Cat
Rat
میتوانید. که در درس بعد در مورد آن توضیح داده میشود، استcollection initializers یکی دیگر از روشهای مقداردهی به یک کلکسیون استفاده از
. نوع مقدار را مشخص میکندTval نوع کلید وTkey . که در فضای نامی ذکر شده قرار دارد استفاده کنیدDictionary<TKey, TVal> از کالس
using System;
using System.Collections.Generic;
243
;)(>Dictionary<string, Animal> animals = new Dictionary<string, Animal
یک دیکشنری تعریف کردهایم که دارای کلیدهایی از نوع 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
244
}
همانطور که مشاهده میکنید ،الزم است که مقادیر را تک به تک به خاصیتها اختصاص دهیم .با استفاده از object initializersمیتوان کد را سادهتر کرد
:
مشاهده میکنید که ،بعد از ایجاد یک شیء از کالس به جای پرانتز از آکوالد استفاده کرده و سپس با لیست کردن خاصیتها مقادیری را که الزم داریم ،به آنها
اختصاص میدهیم .به این نکته نیز توجه کنید که خواص به وسیله کاما از هم جدا میشوند .هنگام استفاده از object initializersسازنده پیشفرض بدون
پارامتر قبل از هر خاصیت مقداردهی شده فراخوانی میشود .از آنجاییکه سازنده پیشفرض قبل از اختصاص مقادیر به خاصیتها اجرا میشود ،میتوانید مقادیری
پیشفرضی به هر یک از خواص اختصاص بدهید ،با این کار الزم نیست که حتماً به همه خواص با استفاده از initializerمقدار اختصاص داده شود .اگر یه
سازنده غیر پیشفرض ( ) non-default constructorبه کالس اضافه کنید باز هم باید یک سازنده بدون پارامتر پیشفرض برای قدرت استفاده از object
initializersوجود داشته باشد .میتوان از object initializersتو در تو نیز استفاده نمود .فرض کنید کالس Sampleمان یک خاصیت از نوع
Animalکه دارای دو خاصیت Nameو Ageهست را دارا میباشد.
نوع دیگر از مقداردهنده ها collection initializersمیباشند collection initializers .بسیار شبیه به array initializersمیباشند با این
تفاوت که در کلکسیونهای عمومی ( )genericاستفاده میشوند.
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
اضافه کرده یا یک سازنده ایجاد کنیم ،که آیتمهایی برای کلکسیون قبول کند.
;))"people.Add(new Person("John
;))"people.Add(new Person("Jenny
;))"people.Add(new Person("Joe
انواع تهی
میتوانید انواع سادهای مانند intو doubleایجاد کنید که مقادیر آنها تهی ( )nullباشد .مقادیر تهی فقط قابلیت ذخیره سازی انواع مرجع مانند رشتهها و سایر
اشیاء را دارند .سی شارپ به شما اجازه میدهد انواع مقداری را تغییر دهید به طوریکه بتوانند به عنوان انواع تهی به کار روند .میتوانید از
> System.Nullable<Tاستفاده کنید که در آن Tنوعی است که به انواع تهی تبدیل میشود.
با استفاده از کد زیر میتوانید تست کنید که آیا متغیر دارای مقدار تهی میباشد یا نه؟
)if (nullDouble.HasValue
{
}
از آنجاییکه ما آنها را به انواع تهی تبدیل کردهایم نمیتوان آنها را در یک متغیر از انواع غیر تهی ذخیره نمود .مثالً کد زیر مجاز نیست :
برای این کار الزم است که ابتدا آنها را به حالت اصلی برگردانید :
اگر بخواهید یک نوع تهی با یک مقدار تهی را به حالت اولیه تبدیل کنید یک استثناء روی میدهد .وقتی دو نوع تهی (به استثنای نوع بولی ؟) را در یک عملیات
در گیر می کنیم ،اگر یکی از عملوندها تهی باشد نتیجه تهی خواهد بود .نتایج ممکن برای نوع بولی ؟ در جدول زیر آمده است :
var1 | var2 var1 & var2 var2 var1
اگر شما بخواهید از nullشدن نتیجه یک عبارت در صورتی که یکی از عملوندهای آن عبارت nullباشد جلوگیری کنید ،باید از عملگر ؟؟ استفاده کنید.
خط دوم نحوهی استفاده از این عملگر را توضیح میدهد .برای نوشتن عبارتی معادل کد باال از یک عملگر 3تایی به صورت زیر استفاده میکنیم.
اگر نتیجه عبارت در سمت چپ عملگر ؟؟ برابر nullباشد نتیجه عبارت سمت راست عملگر و در غیر این صورت نتیجه مقدار سمت چپ عملگر در متغیر
numberذخیره میشود
247
عملگر (??) null Coalescing
عملگر ،null coalescingیک عملگر باینری است که ،برای تشخیص مقدار دو عملوند به کار میرود .کاربرد اصلی این عملگر در قرار دادن یک مقدار
nullableدر یک مقدار non-nullableبا استفاده از یک دستورالعمل ساده است .در زیر نحوه استفاده از عملگر null coalescingنشان داده شده است
:
operand1و operand2میتوانند متغیر ،فراخوانی یک متد و یا یک عبارت باشند .اگر operand1یک متغیر با مقدار تهی باشد و یا فراخوانی یک متد و
یا عبارتی باشد که یک مقدار تهی را تولید کند در این صورت عملگر null coalescingبه سراغ مقدار عملوند operand2میرود .اگر مقدار این عملوند
غیر تهی باشد عملگر null coalescingاز آن در نتیجه محاسبه استفاده میکند .به مثال زیر توجه کنید :
Value is 100
در خط 8مثال باال از عملگر null coalescingاستفاده کردهایم .از آنجاییکه مقدار اولیه num1برابر nullو مقدار num2یک مقدار غیر تهی است ،در
میگیرد. قرار num3 متغیر در num2 مقدار نتیجه
در مثال زیر هم یک متد را فراخوانی میکنیم .البته به طور قطع نمیدانیم که آیا با فراخوانی آن یک مقدار تهی برگشت داده میشود و یا یک مقدار غیر تهی :
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 .نوع delegateی که
مورد استفاده قرار گرفته است را مشخص میکند .از delegateبرای تشخیص امضای کنترل کننده رویدادی که میتواند به آن متصل شود استفاده میشود.
EventNameهم نامی است که برای رویداد در نظر میگیریم .میتوان ارتباط بین delegateو eventرا به صورت زیر خالصه کرد :
249
.1یک delegateتعریف میکنیم.
.2متدهایی که قرار است هنگام وقوع رویداد اجرا شوند را به delegateاضافه میکنیم.
.3یک رویداد ( )eventایجاد میکنیم.
.4یک متد برای اجرای رویداد تعریف میکنیم.
.5آن دسته از متدهای موجود در delegateرا که میخواهیم هنگام وقوع رویداد اجرا شوند یا نشوند را با استفاده از عملگرهای = +و = -به رویداد
معرفی میکنیم.
.6متدی که باعث وقوع رویداد میشود را فراخوانی میکنیم.
برای روشن شدن موارد باال به مثال زیر توجه کنید :
!Hello World
در کد باال یک delegateتعریف کردهایم که مقدار برگشتی آن از نوع voidبوده و هیچ پارامتری قبول نمیکند (خط .)3این امضاء ،همان امضای کنترل
کننده رویداد میباشد .بعد از تعریف delegateیک کالس (خطوط )5-18ایجاد میکنیم .یک کنترل کننده رویداد یا متد به نام )( DisplayMessageکه
امضای آن شبیه امضای delegateاست ایجاد میکنیم (خطوط .)7-10این متد در داخل delegateقرار میگیرد .در خط 12یک رویداد و سپس متدی که
رویداد را به صورت دستی آزاد میکند تعریف میکنیم ( .)14-17رویدادها نمی توانند در خارج از کالسی که در آن قرار دارند آزاد شوند .بنابراین ما از متد ایجاد
شده برای اجرای غیر مستقیم آنها استفاده میکنیم .در داخل متد )( Mainیک نمونه جدید از کالس Messageایجاد میکنیم (خط .)24در خط بعد یک
250
کنترل کننده رویداد به رویداد ما متصل میشود (خط .)25همانطور که در خط 25مشاهده میکنید ،برای اینکه به برنامه بفهمانیم که میخواهیم هنگام وقوع
رویداد چه متدی از delegateاجرا شود باید به صورت زیر عمل کنیم :
به این نکته توجه کنید که استفاده از عملگر =+بدین معنی است که ،میخواهیم یک کنترل کننده رویداد به لیست کنترل کنندههای رویداد اضافه نماییم .یک
نمونه از نماینده (delegate) MessageHandlerایجاد کرده و در داخل آن نام کنترل کننده رویداد را ارسال میکنیم (خط .)25وقتی که متد
)( ExecuteEventفراخوانی میشود ،رویداد آزاد و پیغام نمایش داده میشود (خط .)27در آینده به مفید بودن رویداد در هنگام کار با فرمهای ویندوزی و
صفحات وب پی خواهید برد.
متدهای بی نام ،متدهایی هستند که در واقع تعریف نمیشوند ،بنابراین فقط برای یکبار ( )one-timeمورد استفاده قرار میگیرند .این متدها بیشتر در هنگام کار
با delegateها به کار میروند .در زیر نحوه استفاده از متدهای بی نام نشان داده شده است :
)delegate (parameters
{
//Code for the anonymous method
;}
به عنوان مثال ،میتوانیم یک delegateتعریف کرده و سپس یک شیء از آن ایجاد کنیم و متد بی نام را به آن اختصاص دهیم :
;using System
;)"!ShowMessage("Hello World
}
}
در مثال فوق delegateدارای نوع برگشتی voidو یک پارامتر از نوع رشته میباشد .وقتی یک شیء از delegateایجاد کردیم آنگاه متد بی نام را به آن
ارسال می کنیم .به این نکته توجه کنید که متد بی نام در مثال باال دارای یک پارامتر از نوع رشته مانند delegateاست .نوع برگشتی به صورت خودکار
تشخیص داده میشود .و اگر نوع برگشتی تشخیص داده نشود متد نوع voidرا بر میگرداند .اگر delegateایجاد شده توسط شما دارای نوع برگشتی باشد،
251
متد بی نامی هم که ایجاد میکنید باید دارای دستور returnی باشد که مقدار یک نوع مناسب را برگشت دهد .میتوانید کد باال را به صورت سادهتری بنویسید
:
به نوعی میتوان گفت که هدف اصلی از تعریف متدهای بی نام ،ساده سازی کار با delegateها میباشد.
نوع استنباطی ،به متغیر اجازه میدهد که حدس بزند چه نوع داده ای به آن اختصاص داده شده است .برای ایجاد انواع استنباطی در سی شارپ از کلمه کلیدی
varاستفاده میشود.
سه متغیر باال انواع ضمنی هستند .بدین معنی که ،نوع آنها به بسته به مقادیری که به آنها اختصاص داده میشود به صورت اتوماتیک تغییر میکند (مشخص
میشود) .برای مشخص کردن نوع یک متغیر میتوان به سادگی از کلمه کلیدی varاستفاده کرد .حتی میتوان برای ذخیره نوع objectهم از این کلمه
کلیدی استفاده نمود.
این کلمه کلیدی را می تون برای آرایهها نیز به کار برد :
//OR
252
به این نکته توجه کنید که شما میتوانید بدون ذکر نوع یک متغیر به صورت صریح (مثالً ،)int myIntاز کلمه کلیدی varاستفاده نمایید ،که در نتیجه این
کار ،نوع متغیر بسته به نوع مقداری که به آن اختصاص داده میشود تعیین گردد .از آنجاییکه نوع متغیر بسته به نوع مقداری که به آن اختصاص داده میشود
تعیین میشود ،نمیتوان از متغیری که به آن هیچ مقداری ندادهایم همراه با کلمه کلیدی varاستفاده کنیم .مثالً کد زیر کامپایل نمیشود چون هیچ مقداری به
متغیر اختصاص داده نشده است.
;var someVariable
به عنوان آخرین نکته ،کلمه کلیدی varبرای تعیین نوع (متغیرهای محلی) به کار میرود و نمیتوان از آن به جای نوع برگشتی و نوع پارامترهای یک متد
استفاده نمود.
در سی شارپ می توان انواع بی نامی تعریف کرد ،که یک روش عالی ،برای تعریف انواع موقتی ،جهت ذخیره انواع دادهها میباشد .فرض کنید که ،یک کالس
میخواهید که سه مقدار را در داخل propertyهایش جای دهد.
الزم نیست مانند مثال باال ،یک کالس جهت ذخیره سازی ایجاد کنید ،بلکه میتوانید یک نوع بی نام ایجاد کنید که propertyهایی مانند مثال باال را ،دارا
باشد.
برای این کار باید از کلمه کلیدی 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باشد ،مجبور میشوید که یک متد در کالس دیگر تعریف کنید و آن را به صورت عمومی در دسترس اعضای کالس قرار دهید .به عنوان مثال
یک کالس با نام ExtendClass1با سطح دسترسی staticمینویسیم که دارای متدی به نام Averageو سطح دسترسی staticاست .به این نکته
توجه کنید که متد )( Averageیک نمونه از کالس Class1را به عنوان پارامتر میگیرد.
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تعریف شود. •
خود متد باید به صورت staticتعریف شود. •
اولین پارامتر متد توسعه یافته باید با کلمه کلیدی thisشروع و بعد از این کلمه نام کالسی که میخواهیم متد به آن اضافه شود ،ذکر شود. •
کد زیر همه برنامه را که شامل کالس Class1و متد توسعه یافته )( Averageتعریف شده در کالس ExtendClass1را نشان میدهد .به این نکته
توجه کنید که که متد )( Averageدقیقاً طوری فراخوانی شده است که انگار یک عضو نمونه از کالس Class1است .کالسهای Class1و
ExtendClass1هر دو با هم مانند یک کالس با سه متد عمل میکنند.
;using System
namespace ExtensionMethods
{
255
D2 = d2;
D3 = d3;
}
public double Sum()
{
return D1 + D2 + D3;
}
}
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( عبارات المبدا
. ارجاع داده شده است استفاده شده استdelegate
using System;
;)"!ShowMessage("Hello World
}
}
به وسیله عبارات المبدا میتوان کد باال را به صورت سادهتری نوشت :
;using System
;)"!ShowMessage("Hello World
}
}
)MyDelegate del = delegate(int x ; } ;{ return x + 1 متد بی نام //
MyLambda = lam ( ; } ;x) => { return x + 1 عبارت المبدا //
در عبارت المبدا ابتدا پارامترها را بدون ذکر نوعشان مینویسیم و بعد از عملگر >= استفاده میکنیم .سپس دستوراتی را که قرار است اجرا شوند را مینویسیم.
نوع پارامترها به صورت خودکار به وسیله کامپایلر تشخیص داده میشود .البته امضاء عبارات المبدا باید شبیه به امضاء delegateباشد .عبارات المبدا دارای
اشکال زیادی هستند .به عنوان مثال در مثال باال از یک عبارت المبدایی استفاده کردهایم که دارای یک دستور ساده اجرایی است .اگر delegateشما برای
عبارت المبدا هیچ پارامتری نداشته باشد ،همه کاری که الزم است نجام دهید این است که هیچ پارامتری در داخل عبارت المبدا قرار ندهید.
به این نکته توجه کنید که شما میتوانید نوع پارامترهای عبارت المبدا را نشان دهید.
اگر نوع یک پارامتر را مشخص کنید ،باید نوع سایر پارامترها را نیز مشخص کنید .به عنوان مثال نمیتوانید به صورت زیر عمل کنید :
اگر عبارات المبدای شما دارای چندین دستور اجرایی باشند میتوانید آنها را داخل آکوالد قرار دهید .به عبارت المبدایی که دارای آکوالد باشد دستور المبدا می
گویند.
257
{
;)Console.WriteLine(message
;)"Console.WriteLine("Some more message
}
در زیر مثالی از یک عبارت المبدا که دارای مقدار برگشتی است نشان داده شده است :
به این نکته توجه کنید که هنگام استفاده از دستور returnباید همیشه از دستورات المبدایی استفاده کنید که دارای آکوالد میباشند .اگر یک عبارت المبدا فقط
دارای یک دستور returnساده باشد میتوانید به سادگی آن را به expression lambdaتبدیل کنید.
به این نکته توجه کنید که استفاده از پرانتز در کد باال برای فهم بهتر آن است .اگر یک عبارت المبدا دارای یک پارامتر ساده و یک دستور returnاست،
میتوانید برای سادگی بیشتر پرانتزها را حذف نمایید:
ولی اگر یک عبارت المبدا دارای 2یا تعداد بیشتری پارامتر باشد باید انها را داخل پرانتز قرار دهید.
عبارت المبدای باال دارای دو پارامتر است و حاصل جمع آنها را بر میگرداند.
با استفاده از عبارات المبدا راحتتر می توان متدهای بی نام را به عنوان آرگومان به دیگر متدها ارسال کرد .به مثال زیر توجه کنید :
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:
Expression-Bodied Members
Expression-bodied membersیکی از ویژگیهای سی شارپ 6بوده ،که به شما اجازه استفاده از المبدا ،برای کدنویسی راحتتر متدها ،خاصیتها،
سربارگذاری عملگرها و ایندکسرهای یک کالس را میدهد .با وجود این ویژگی شما به جای نوشتن بدنه یک عضو میتوانید از عالمت المبدا استفاده کنید .به
عنوان مثال ،متد زیر را در نظر بگیرید که دو پارامتر را دریافت کرده و جمع آنها را بر میگرداند :
با استفاده از ویژگی Expression-bodied membersشما میتوانید کد باال را خالصهتر کرده و به صورت زیر بنویسید :
همانطور که در کد باال مشاهده میکنید ،امضای متد را دستکاری نمیکنیم اما بدنه را با عالمت => شروع و سپس عبارتی که جمع دو مقدار را بر میگرداند را
مینویسیم .به این نکته توجه کنید که دیگر الزم نیست از کلمه کلیدی returnاستفاده کنیم .برای تعریف خاصیتها هم میتوانیم از این ویژگی استفاده کنیم.
مثالً در کد زیر یک خاصیت فقط خواندنی که نام کامل یک شخص را بر میگرداند تعریف کردهایم :
259
get
{
;return FirstName + " " + LastName
}
}
برای متدهایی هم که مقدار برگشتی آنها از نوع viodاست و دارای یک خط در بدنه هستند هم میتوان از این ویژگی به صورت زیر استفاده کرد :
// Indexer
;]public int this[int index] => InternalCollection[index
ممکن است که این سؤال برایتان پیش بیاید که آیا میتوان از ویژگی در اعضایی که دارای چندین دستور در بدنه خود هستند استفاده کرد .جواب منفی است .این
ویژگی فقط برای اعضایی به کار میرود که دارای یک دستور ساده در بدنه خود هستند.
استفاده از کالسهای استاتیک در فضای نام ،یکی از ویژگیهایی است که در 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;
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;
}
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
}
}
}
}
دستور using
کاربرد اصلی دستور usingنابود کردن اشیاء و آزاد کردن فضای حافظه است .همانطور که می دانید بعد از ساخت اشیاء و عدم استفاده از آن باید آن را از حافظه
خارج کنیم تا دوباره آن بخش از حافظه مورد استفاده قرار گیرد .اگر چه garbage collectorیا زباله روب حافظه این کار را به طور اتوماتیک انجام میدهد،
ولی مشخص نیست garbage collectorچه زمانی رخ میدهد و تا زمانی که garbage collectorکار خود را شروع نکند ،همچنان حافظه بال استفاده
میماند .در سی شارپ ،شما می توانید هر لحظه که الزم باشد ،شیء بال استفاده را از حافظه پاک کنید (اصطالحاٌ Disposeکنید) .ساختار کلی دستور using
به صورت زیر است :
)(using
{
...
}
این دستور ،به دستور finally…tryترجمه میشود .پس دو کد زیر با هم برابرند :
اگر بخواهیم از کالسمان ( )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
}
}
}
}
همانطور که می دانید وقتی یک کالس از کالس دیگر ارث بری میکند ،به تمام اعضای publicآن کالس دسترسی مییابد .اما در برخی موارد ،ممکن است
کالس فرزند دارای متدی باشد که نام و امضای آن شبیه به متدی در کالس پدر باشد .حال اگر یک شیء از کالس فرزند ایجاد و متد را فراخوانی کنید ،در اصل
متد کالس فرزند فراخوانی میشود ،چونکه کامپایلر سی شارپ به طور خودکار متد کالس پایه را مخفی میکند .هر چند که سی شارپ این کار را خودکار انجام
میدهد ولی بهتر است شما این کار را به صورت دستی و با اضافه کردن کلمه کلیدی newقبل از نوع برگشتی متد انجام دهید ،به این کار مخفی کردن متد یا
Method Hidingمی گویند ،چون که شما عمداً متد کالس پایه را مخفی کردهاید :
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:
;)(base.ShowMessage
;)(((Parent)child1).ShowMessage
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این کالس میباشد .در این صورت اگر خط زیر را جایگزین خط باال کنید ،همان نتیجه حاصل
میشود :
به این نکته توجه کنید که خروجی متدها میتواند از نوع 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.ReadKey
}
}
}
در مثال باال یک متد به نام () GetPersonبا نوع خروجی > Tuple<string, stringتعریف کردهایم .در بدنه آن یک شیء از نوع Tuple<string,
> stringایجاد کردهایم و آنرا برگشت میدهیم .در متد () Mainخروجی متد را در متغیر personقرار داده و مقدار خاصیتهای آنرا در خط بعدی نمایش
میدهیم.
267
توابع محلی ()Local Functions
Local Functionها امکان تعریف یک متد در داخل متد دیگر را فراهم می کنند .شما می توانید با استفاده از این قابلیت در C# 7.0یک متد را در داخل
یک مت د موجود تعریف کنید .به این نکته توجه کنید که ،برای استفاده از این قابلیت های جدید باید آخرین نسخه ویژوال استودیو ( Visual Studio 2015
)Preview 4را بر روی سیستم نصب کنید :
;))Console.WriteLine(LocalFunction(10
}
در مثال باال ،یک متد به نام LocalFunctionرا در “داخل” بدنه ی متد Mainتعریف کرده ایم ،سپس آنرا فراخوانی و خروجی آنرا بر روی صفحه ی
نمایش چاپ می کنیم .در متد های محلی می توانید از متغیرهایی که قبل از تعریف متد ،تعریف شده اند استفاده کنید :
در مثال باال ،در داخل متد محلی از یک متغیر به نام localVarکه قبل از متد تعریف شده است استفاده کرده ایم.
گاهی در برنامه های خود نیاز به ایجاد اشیایی داریم که وضعیت داخلی این اشیاء (مقادیر فیلد ها ،خصیصه ها و …) بعد از ایجاد شی قابل تغییر نباشد .در
چارچوب دات نت ،کالس stringبه این صورت پیاده سازی شده است .زمانی که شما یک مقدار رشته ای را در یک متغیر از نوع stringقرار می دهید و بعدا
آن مقدار را تغییر می دهید ،کامپایلر C#در پشت صحنه یک شیء با مقدار جدید می سازد و در فیلد مورد نظر قرار می دهد و شیء قبلی را دور می اندازد (توسط
garbage collectorپاک می کند) :
268
در کد زیر شما یک کالس با نام Personرا مشاهده می کنید که شامل دو فیلد با نام های nameو familyاست .این دو فیلد به صورت readonlyو از
نوع stringتعریف شده اند.فیلد های readonlyتنها می توانند در خط تعریف فیلد یا در سازنده کالس مقدار دهی شوند .سپس برای این دو فیلد ،خصوصیات
متناظری ایجاد می کنیم .خصوصیت هم فقط از قسمت getتشکیل شده است و نباید قسمت setداشته باشد .زیرا کاربر بعد از ایجاد شیء نباید مقادیر درون
شیء را تغییر دهد .مقادیر مورد نظر را از طریق پارامتر های سازنده کالس می گیریم و در فیلدها قرار می دهیم :
;"person1.Name = "Jack
در کد باال نمی توانیم بعد از ایجاد شیء مقادیر خصوصیات آن را تغییر دهیم.زیرا خصوصیات فقط از قسمت getتشکیل شده اند .پس خط قرمز در مثال باال غیر
مجاز می باشد.
269