آموزش سی شارپ - قسمت سي و يکم

در قسمت قبلی در رابطه با اینکه اينترفيس ها را به عنوان سرويس در نظر بگيريم صحبت شد و گفتيم که به عنوان مثال در صورتيکه شما از اينترفيس IComparable به ارث بريد و متد CompareTo را پياده سازی کنيد آنگاه مي توانيد از سرويس Sort در کلاس ArrayList استفاده کنيد. اما چرا؟

در واقع وقتي شما متد Sort را فراخواني مي کنيد در کلاس ArrayList فرض را بر این مي گذارد که تک تک اشياي داخل آرایه از این اينترفيس به ارث رفته اند در نتيجه شي داخل آرايه را (که يک object مي باشد) Cast به IComparable می کند در نتيجه مي تواند از متد CompareTo استفاده کرده و مقايسه مورد نظر را انجام دهد. حالا در صورتيکه شيء شما از اين اينترفيس به ارث نرفته باشد يک خطا از نوع InvalidOperationException دريافت خواهید کرد.



نمونه های بسياري وجود دارند که شما با پياده سازي يک يا چند Interface امکان استفاده از يک موضوع (به صورت سرويس) را بهره مند مي شويد. البته به اين نکته توجه داشته باشيد که روش پياده سازي و Logic آن کاملا در اختيار شماست و در صورتيکه درست پياده سازي نشود مسئوليت خطا های احتمالی و يا عملکرد نادرست به عهده شما مي باشد.

فرض کنيد که شما يک کلاس داريد که وظيفه آن چاپ کردن اطلاعات اشياء ديگر توسط يک چاپگر مي باشد. نکته مهم اين است که شما مي خواهيد اين سرويس (یعني چاپ کردن توسط يک چاپگر خاص) را در اختيار همه قرار دهيد. براي همين منظور کافيست که يک interface طراحي کنيد و يک متد به نام Print در آن تعريف کنيد.



حالا کافيست که در اين کلاس از کاربران انتظار ارسال کلاس هايي را داشته باشيد که از اين اينترفيس به ارث رفته اند و در صورتيکه يک شيء به متد شما ارسال شود که از اين اينترفيس به ارث نرفته باشد شما هم يک خطا از نوع InvalidOperationException پرتاب خواهيد کرد.



مثال هاي بسياري از اين دست در رابطه با استفاده از اينترفيس ها به عنوان سرويس مي توان نوشت. در پست بعدي در رابطه با استفاده از اينترفيس ها برای پياده سازي توارث چندگانه خواهم نوشت.

بارگزاري مثال
ادامه دارد....

آموزش سی شارپ - قسمت بیست و نهم

در قسمت قبلی در رابطه با interface ها و اینکه چگونه ایجادشان کنیم صحبت کردیم. حالا اجازه بدین در رابطه با اینکه چرا و به چه دلایلی از interface ها استفاده می کنیم صحبت کنیم.

موارد استفاده اينترفيس ها - Interface Usage

همانطور که قبلا هم اشاره شد و از کلمه inteface بر می آید در واقع اینترفيس ها یک واسط یا قرارداد هستند. اما برای اینکه راحت تر دلایل استفاده از آن ها را در زبان برنامه نویسی سی شارپ و دنیای شي گرایی متوجه بشیم من سه دلیل برای استفاده از اینترفیس ها بیان می کنم:

  1. اینترفیس ها به عنوان استاندارد - Interface as Standard
  2. اینترفیس ها به عنوان سرویس - Interface as Service
  3. اینترفیس ها برای حل مشکل توارث چندگانه - Interface for Multiple Inheritance


اینترفيس ها به عنوان استاندارد - Interface as Standard
فرض بفرمائید که شما قصد تهیه یک Total System یا یک مجموعه نرم افزار یکپارچه را دارید. در این مجموعه نرم افزار Entity ها بسياری وجود دارند و در فاز تحلیل و طراحی نسبت به شناخت و طراحی آن ها اقدام کرده اید. وظيفه اجراي هر یک از این SubSystem ها توسط یک گروه از افراد در سازمان شما می باشد.
حالا موجودیتی مثل افراد (Person) را در نظر بگیرید که در تمامی زیر سيستم های شما وجود دارد و فقط با جزئیات مختلف نمود پیدا می کند. مثلا در زیر سيستم حسابداری به عنوان مشتری با اطلاعات خاص مشتري ها , در سيستم پرسنلی به عنوان کارمند با اطلاعات خاص هر کارمند و ....
نکته اینجاست که اگر قرار باشد این موجودیت ها بین زیر سیستم های این نرم افزار یکپارچه قابلیت تبادل داشته باشند باید یک استاندارد خاص در نظر گرفته شود که تمام این موجودیت های به نحوی به آن قابل تبدیل باشند. پس در این حالت یک inteface با تمامی اطلاعات مشترکي که موجودیت انسان در تمام این زیر سيستم ها دارد در نظر گرفته می شود و تمامی زير سيستم ها موظف به پیاده سازی آن توسط کلاس های خاص خود می شوند. و در صورتیکه لازم باشد یک موجود از این زير سيستم به زيرسيستم دیگر ارجاء شود به راحتی به IPerson تبدیل شده و در زير سيستم بعدی به عنوان يک IPerson دریافت و تبدیل می شود.



البته این روش نه تنها در سي شارپ بلکه در جاهای دیگر نيز استفاده دارد. به عنوان مثال وقتی قرار به استفاده از تکنولوژی Bluetooth شد 5 شرکت پيشتاز این تکنولوژی یعنی Microsoft , Ericsson و سه شرکت دیگر برای استاندارد سازی این تکنولوژی سميناري تشکیل دادند و توافق نامه ای امضاء کردند که طبق آن تمامی شرکت ها موظف به توليد محصولاتي با رعايت یکسری استاندارد شدند و البته همه آن ها می توانستند برای توسعه اين تکنولوژی اقدام کنند. در نتيجه تمامي محصولاتي که اين شرايط را رعايت کنند مي توانند با يکديگر ارتباط داشته باشند.

ادامه دارد...

آموزش سي شارپ - قسمت بيست و هشتم

Interface ها در سي شارپ
در پست هاي قبلي به دو سطح از Inheritance اشاره كرديم. در سطح اول يك كلاس را از يك كلاس ديگر به صورت معمولي به ارث برديم. يعني مثلا كلاس Emp را از كلاس Person به ارث برديم در حالتيكه ساختن شيء‌از هر دو آن ها كاربري و منطقي بود.
سپس يك سطح انتزاعي تر كلاس هاي abstract را بررسي كرديم. كلاس Emp را به صورت abstract تعريف كرديم و كلاس هاي MonthlyEmp و HourlyEmp را از آن به ارث برديم.

حالا می خواهیم به بالاترین سطح انتزاعی در سی شارپ یعنی Interface ها بپردازیم. در بررسی اینترفیس ها من ابتدا به تعریف آن ها اشاره می کنم. سپس روش و Syntax استفاده از آن ها و در نهایت موارد استفاده از آن را بررسی می کنم.

اينترفيس ها قرارداد هایی هستند که اعلام می کنند این نوع های داده ای دارای چه امکاناتی می باشند. اما روش پیاده سازی آن ها را اعلام نمی کنند. در واقع در اینترفیس ها شما هیچ گونه پیاده سازی ندارید و فقط اعلام می کنید که نوع شما دارای چه "متد ها" , "پراپرتی ها" , "ایندکس ها" و "رویدادهایی" است.

برای تعریف اينترفيس ها در سي شارپ باید در سطح namespace همانند یک کلاس ولی با استفاده از keyword ی به نام interface.



همانطور که در تصویر بالا مشاهده می کنین در اینترفيس ها شما فقط به تعریف ها می پردازید و اجازه ایجاد بدنه متد ها و property ها را ندارید. در تعریف interface ها قوانین زیر وجود دارند:
  • امکان استفاده از access modifier ها وجود ندارد. (در واقع تمامی اعضاء یک interface) به صورت public هستند ولی کلمه public نوشته نمی شود.
  • در اينترفيس ها Constructor نداريم.
  • تمامی Property و Method و Indexer ها به صورت abstract و بدون پیاده سازی هستند.
  • امکان استفاده از field ها وجود ندارد.
ادامه دارد ...

آموزش سی شارپ - قسمت بیست و هفتم

کلاس های Abstract در سي شارپ

قبلا در مورد Inheritance و ارث بری در سی شارپ صحبت کردم. گفتیم که در سی شارپ شما می توانید از یک کلاس به ارث برید و در صورت نیاز رفتارهای آن را override یا hide نمائید. فرض کنید که در طراحی نرم افزار پرسنلی شرکت دارید. در این سازمان دو نوع کارمند وجود دارد. کارمند ساعتی و کارمند حقوق بگیر ماهیانه. کارمندان را چگونه طراحی می کنید؟

به نظر من می توانید یک کلاس به نام Employee ایجاد کنید و اطلاعات مشترک بین هر دو نوع کارمند را در این کلاس ایجاد کنین. من در این کلاس اطلاعات نام , نام خانوادگی, سن, کد کارمندی , حقوق و یک متد برای پرداخت حقوق ایجاد کردم. سپس دو کلاس MonthlyEmployee و HourlyEmployee را از کلاس Employee به ارث بردم. نکته ای که وجود دارد این است که در کلاس Employee به وجود Salary و PrintSalary نیاز دارم اما نمی دانم که برای موجودیتی به نام کارمند که در واقع وجود خارجی ندارد(چون در سازمان من همه کارمندان یا ساعتی هستند یا حقوق بگیر و شیء از جنس کارمند محض وجود ندارد) و اینکه من نمی دانم که حقوق این نوع کارمند چگونه پرداخت و محاسبه می شود و در واقع حقوق برای کارمند محض معنی ندارد و من صرفا این خاصیت و متد را برای override کردن در کلاس های فرزند ایجاد کرده ام.

در چنین مواردی شما می توانید متد ها و property هایی که در کلاس پایه تان امکان پیاده سازیشان وجود ندارد را به صورت abstract تعریف کنین. در واقع با این کار به کامپایلر سی شارپ می فهمانید که این خاصیت یا متد صرفا به جهت override شدن در کلاس های فزرند ایجاد شده است. برای اینکه یک عضو abstract تعریف کنین باید کلمه abstract را در تعریف آن آورده و بدنه آن متد یا Property را حذف نمائید:


دقت فرمائید که وقتی یک کلاس دارای عضو abstract باشد آن کلاس نیز باید abstract شود.



خصوصیات کلاس های abstract:
  • وقتی کلاسی دارای یک عضو abstract باشد آن کلاس هم باید abstract شود.
  • وقتی یک کلاس به صورت abstract ایجاد شد از آن کلاس نمی توان شیء جدید ساخت.
  • وقتی از یک کلاس abstract به ارث می روید باید عضو های انتزاعی (abstract members) آن را override کنید.
  • کلمه abstract برای یک عضو (Member) کارایی کلمه virtual را نیز داراست.
  • وقتی از یک کلاس abstract به ارث می روید در صورتیکه حتی یکی از عضوهای abstract آن را override نکنید آن کلاس هم باید abstract شود.
  • اگر از یک کلاس که یک کلاس abstract را پیاده سازی کرده به ارث برویم می توانیم دوباره اعضاء abstract آن را override کنیم.
  • abstract کلاس ها می توانند دارای constructor باشند.
دانلود مثال abstract class ها

ادامه دارد...

آموزش سي شارپ - قسمت بيست و ششم

ايجاد خطاهي خاص - Custom Exception Definition
خيلي اوقات شما مي خواهيد همراه با اعلام خطا اطلاعات ديگري را كه فقط هنگام ايجاد خطا در اختيارتان هست را هم داشته باشيد و اعلام نمايد. براي اين منظور بايد يك كلاس جديد ايجاد كرده و آن كلاس را از كلاس Exception به ارث ببريد. سپس اطلاعات اضافه مورد نياز خود را در آن كلاس به صورت ReadOnly Property تعريف كرده و آن ها را با استفاده از Constructor كلاستان مقدار دهي نمايد.



! همانطور كه مي بينيد من در زمان ايجاد شدن شيء از اين كلاس مقدار message‌ را به Contrcutor كلاس پدر پاس مي كنم.

در مثال زير يك كلاس به نام Person‌ وجود دارد. تصميم گرفتم كه وقتي مقداري بيش از 100 و يا كمتر از 0 براي سن درنظر گرفته شد يك خطا پرتاب كنم. نكته اي كه وجود دارد اين است كه مي خواهم همزمان اعلام كنم كه چه سني براي چه كسي در نظر گرفته شده است كه خطا توليد شده است.
حالا در كلاس Person روي Property Age وقتي كاربر سني بيش از 100 يا كمتر از 0 را ست كند يك خطا از نوع InvalidAgeException‌ پرتاب خواهم كرد:


در نتيجه وقتي به يك شيء از اين كلاس مقداري نامعتبر براي سن مشخص كنيم كاربر خطا دريافت خواهد كرد. نكته مهم اين است كه شما مي توانين اطلاعات فردي كه خطا بر روي آن اعلام شده و مقداري كه به عنوان سن براي او در نظر گرفته شده بود را هم داشته باشيد و نمايش دهيد.



Download Sample Code

ادامه دارد...

آموزش سي شارپ - قسمت بيست و پنجم

تشخيص نوع خطا توسط Catch

همانطور كه در قسمت قبل اشاره شد شما مي توانيد با استفاده از Try Catch‌ در مقابل خطاي احتمالي عكس العمل نشان دهيد. حالا به مثال زير دقت كنين:



در اين مثال كاربر شما بايد دو عدد را تايپ كرده و نرم افزار اين اعداد را كه در غالب رشته اي (string) از متد ReadLine كلاس Console ‌گرفته شده اند - و بعد با استفاده از متد Parse‌ به عدد تبديل گشته اند - را بر هم تقسيم كرده و نتيجه را به شما نشان مي دهد.
با توجه به كد بالا من مي توانم احتمال بروز دو نوع خطا را تشخيص دهم:
1. كاربر به جاي تايپ كردن يك عدد از رشته ها استفاده كند (مثلا بنويسد Ali)
2. كاربر يك عدد را بر 0 تقسيم نمائيد (‌در دات نت و بيشتر زبان هاي برنامه نويسي هيچ عددي را بر 0 نمي توان تقسيم كرد و در صورتيكه اين كار را انجام دهيم يك خطا از نوع DividedByZeroException پرتاب خواهد شد)


نكته اي كه وجود دارد اين است كه من مي خواهم در مقابل هريك از اين نوع هاي خطا عكس العمل مناسب خودش را نشان دهم. براي اينكه بتوانم اين كار را انجام دهم بايد از چندين قسمت Catch استفاده كنم و در هر قسمت يك نوع از خطا ها را كنترل كنم:



همانطور كه مي بينيد من در ابتدا خطاي نوع FormatException را كنترل مي كنم كه در مواقعي Raise مي شود كه شما يك رشته نا صحيح را با عدد تبديل كنين. مثالا سعي كنين حرف ABD را به عدد تبديل كنين.
در قسمت دوم من يك خطا از نوع DividedByZeroException را كنترل مي كنم كه در مواقعي ايجاد مي شود كه شما يك عدد را بر 0 تقسيم نمائيد. و در نهايت در سومین Catch هر نوع خطا ديگري كه در اين دو نوع قرار نگيرد را کنترل و یک متن عمومی را نمایش می دهد. در واقع شما می توانین با استفاده از چند قسمت Catch هر نوع خطای احتمالی را گرفته و عکس العمل مناسب در مقابل آن نمایش دهید.

به منظور دریافت متن اصلی خطا و اطلاعات دیگر خطای اصلی , شما می توانید در مقابل هر یک یک متغییر تعریف کرده و از اطلاعات آن استفاده نمائید.



بارگزاری مثال
ادامه دارد...

آموزش سی شارپ - قسمت بيست و چهارم

كنترل خطاها در سي شارپ - Exception Handling in CSharp
در تمامي زبان هاي برنامه نويسي روش هايي براي مقابله با خطا ها وجود دارد. عموما خطا ها را از ديد زمان وقوع به دو دسته Compile Time Errors و RunTime Error ها تقسيم كرد. خطا هاي گروه اول يا همان خطاهاي زمان كامپايل توسط Compiler تشخيص داده و به كاربر نمايش داده مي شوند. خطاهايي از قبيل استفاده از يك متغييري كه مقدار دهي نشده است يا اشتباه در Syntax و ....
خطاهاي زمان اجرا عموما خطاهايي هستند كه در زمان كامپايل توسط Compiler تشخيص داده نشده اند و در زمان اجراي نرم افزار بروز مي كنند. خطاهایی مثل مشکل در اتصال به بانک اطلاعاتی , ورود اطلاعات اشتباه توسط کاربر , عدم دسترسی به فایل مورد نظر و ....
اصولا هر برنامه نویس در هنگام نوشتن خطوط کد خود می تواند احتمال وقوع خطا را پیش بینی کند مثلا در مثال زیر من از کاربر انتظار دارم تا یک عدد را برای من تایپ کند:



اما می توانم حدس بزنم که کاربر می تواند به جای 10 کلمه "ALI" را سهوا یا عمدا تایپ نماید. که در این صورت نرم افزار من دچار اشکال شده و از برنامه خارج خواهد شد.

در سی شارپ برای اینکه بتوانیم خطا ها را کنترل کنیم , خطوطی را که احتمال وقوع خطا در آن ها زیاد است را در try catch می نویسیم.
برای اینکار کافی است که به صورت زیر عمل کنیم:



همانطور که می بینید من خطوطی از کد که احتمال خطا دارد را داخل بلاک try قرار دادم و عکس العمل خودم در موقع بروز خطا را نیز در بلاک catch. در واقع در صورتیکه در هر یک از خطوط داخل block try دچار خطا شویم به قسمت catch ارجاع داده خواهیم شد و می توانیم آنجا عکس العمل لازمه را نشان دهیم.

در سی شارپ و در namespace ی به نام System یک کلاس به نام Exception وجود دارد که در حقیقت base classی برای تمام انواع خطا ها در سی شارپ می باشد. به این معنا که تمامی خطاهایی که در سی شارپ وجود دارند از Exception به ارث رفته اند و در نتیجه تمامی آنها به نوع Exception می باشند. برای اینکه بتونین لیست Exception ها را ببینین کافیه که از منوی Debug گزینه Exception را کلیک کنین تا لیست Exception ها را به تفکیک namespace ملاحظه بفرمائید. (می تونین از Alt + Ctrl + E به عنوان Shortcut استفاده کنین).



با توجه به مثال اولی که نوشتیم تا اینجا ما توانستیم در مواقعی که احتمال وقوع خطا وجود دارد با استفاده از try و Catch مانع از بسته شدن نرم افزارمان یا به اصطلاح crash شدن آن شویم. مرحله بعدی تشخیص دادن نوع خطا و در نهایت نشان دادن عکس العمل مناسب در مقابل خطای مورد نظر است.

تولید خطا در سی شارپ
اما قبلا از اینکه به این موارد بپردازیم اجازه بدین بررسی کنیم که در سی شارپ چطور می توانیم تولید خطا کنیم؟
برای ایجاد یک خطا در زمان runtime در سی شارپ کافی است که یک شیء از جنس Exception را بوسیله کلمه کلیدی throw پرتاب کنیم. به مثال زیر دقت کنین:



در نتیجه کد بالا که در واقع تولید یک خطا را نمایش می دهد خطای زیر از نرم افزار ایجاد شده و نرم افزار بسته خواهد شد:



در واقع وقتی شما با یک خطا برخورد می کنید به این معنی است که یک شیء از جنس Exception یا کلاس هایی که از Exception به ارث رفته اند توسط کلمه کلیدی throw پرتاب شده است. حالا اگر شما از block های try , catch استفاده کنین می توانین در مقابل آن خطا عکس العمل نشان دهید:



در تصویر بالا من هنگام پرتاب کردن خطا یک متن را به عنوان توضیح خطا در سازنده کلاس Exception قرار داده ام که این متن را بعد ها از طریق متغییر Message می توانم به دست بیاورم. اما نکته ای که وجود دارد این است که برای اینکه بتوانید متن خطا و محل آن را به دست بیاورید به آن شیء ای که پرتاب شده است نیاز دارید. پس من با این یک متغییر به آن شیء دسترسی پیدا می کنم:

همانطور که می بینین متنی که در شیء پرتاب شده اعلام شده است در داخل متغییر Message در شیء ex قرار گرفته است و من می توانم آن را نمایش دهم.

همچنین شما می توانین از طریق متغییر StackTrace کلاس Exception مسیر اتقاقات رخ داده تا زمان بروز خطا را در غالب یک رشته داشته باشین:



ادامه دارد...

مجموعه آموزش سی شارپ

همانطوری که وعده داده بودم مجموعه نوشته هایی که طی چند ماه اخیر با عنوان آموزش سی شارپ نوشته ام را در قالب یک فایل PDF برای سهولت دسترسی در اختیارتان قرار می دهم. فایل جاری شامل بیست قسمت از آموزش های سی شارپ می باشد که به مرور زمان تکمیل تر خواهد شد. امیدوارم که مفید باشد و دوستان هم مشکلاتش را متذکر شوند.

لینک دانلود فایل آموزش سی شارپ
http://www.tabatabaei.info/csharpsamples/CSharpTutorial.pdf

آموزش سی شارپ - قسمت بیست و سوم

بازنويسي عملگرها در سي شارپ - Operator Overloading in csharp

تمامي عملگرها (operators) در سي شارپ داراي رفتار هاي از پيش تعيين شده اي هستند و شما مي توانيد از اين عملگرها در عبارت هاي خود استفاده کنين:

int i = 10;
int j = 20;
int m = i * j / 2 + 14;
Console.WriteLine("m is :{0}",m);


اما اگر شما عبارت زير را بنويسيد چطور؟

Person p = new Person("Ali",20);
Person p2 = new Person("Reza",30);
Person p3 = p + p2;
Console.WriteLine("Name: {0}, Age:{1}",p3.Name , p3.Age);


در صورتيکه اين کد را Compile کنين متوجه يک خطاي Compile Time خواهيد شد که به شما توضيح مي دهد که امکان جمع بستن دو Person با يکديگر وجود ندارد يا به عبارت ديگر عملگر + براي Person تعريف نشده است.
در سي شارپ شما مي توانين بسياري از عملگرها را دوباره نويسي کنين به عبارت ديگر شما مي توانين در مواقع لزوم تعريف جديد از يک عملگر در سي شارپ داشته باشيم. در تصوير زير ليست عملگرها به همراه توضيحاتي راجع به امکان بازنويسي شان مي بينيد.



همانطور که در تصوير مشخص است شما نمي توانين تمام عملگرها را دوباره نويسي کنين.
در سي شارپ يک کلمه کليدي به نام operator وجود دارد که براي بازنويسي عملگرها بايد از آن استفاده کنيم. به عنوان مثال براي اينکه مثالي که در ابتدا نوشتيم درست عمل کند و وقتي عبارت بالا را اجرا مي کنيم يک شيء جديد از جنس Person ايجاد شود که نامش از جمع بستن نام اين دو فرد و سنش از جمع بستن سن اين دو فرد تشکيل شود من در کلاس Person اين کد را مي نويسم:

public static Person operator +(Person p1, Person p2)
{
Person p = new Person();
p.Name = p1.Name + " " + p2.Name;
p.Age = p1.Age + p2.Age;
return p;
}

دقت بفرمائيد که حاصل جمع دو شيء از جنس Person يک Person مي باشد و من در پياده سازي عملگر + يک فرد جديد ساخته ام. اما اگر بخواهيم عملگر == يا همان برابري را دوباره نويسي کنيم بايد دقت کنيم که خروجي آن بايد يک عبارت true /false و از جنس bool باشد. در نتيجه اگر من بخواهم که مبناي مقايسه دو شيء از جنس Person را براساس نامشان قرار دهم از اين کد استفاده مي کنم:

public static bool operator ==(Person p1, Person p2)
{
return p1.Name == p2.Name;
}

نکته مهم در اين مثال اين است که شما وقتي عملگر == (برابري) را دوباره نويسي مي کنين بايد عملگر != (نابرابري) را هم دوباره نويسي کنين:

public static bool operator !=(Person p1, Person p2)
{
return !p1==p2;
}


بارگزاري مثال

آموزش سي شارپ - قسمت بيست و دوم

فراخواني سازنده ها - Constructor Calling

وقتي از يك كلاس كه يك كلاس ديگر به ارث رفته است , شيء‌ مي سازيم در واقع متد سازنده آن كلاس و تمامي كلاس هايي كه به عنوان پدر اين كلاس مطرح هستند را نيز فراخواني مي نمائيم. به عنوان مثال كلاس Customer از كلاس Person به ارث رفته است. در كلاس Person من دو نوع Constructor‌ دارم. يكي همان Default Constructor است كه به صورت public و بدون پارامتر تعريف شده و ديگر داراي دو پارامتر است. يكي از جنس String‌ كه نام فرد است و ديگري از جنس int كه سن فرد مي باشد:

public class Person
{
public int Age;
public string Name;

public Person()
{
Console.WriteLine("Default Constructor of Person Called");
}
public Person(string Name, int Age)
{
this.Name = Name;
this.Age = Age;
Console.WriteLine("2nd Constructor of Person Called");
}

public virtual void Print()
{
Console.WriteLine("Name: {0}, Age: {1}", Name, Age);
}
}


همانطور كه مي بينيد من براي اينكه مشخص بشه كه از كدام Cosntructor‌ استفاده مي شود در هر دو Constructor‌ يك جمله چاپ مي كنم.

حالا كلاس Customer‌ را از كلاس Person‌ به ارث مي بريم:

public class Customer : Person
{
public decimal Credit;

override public void Print()
{
Console.WriteLine)"Name: {0}, Age: {1}, Credit: {2}", Name, Age, Credit);
}
}


حالا براي تست يك شيء از كلاس Customer ايجاد مي كنم:

Customer C = new Customer();
c.Name = "Ali";
c.Age = 20;
c.Credit = 2000;
c.Print();


كه در نتيجه در محيط Console‌ خروجي شبيه به اين خواهيم داشت:



همانطور كه در خروجي هم مشخص شده است , با اينكه من Constructor كلاس فرزند را فراخوني كردم اما Default Constructor كلاس پدر نيز فراخواني شده است.

نكته اي كه وجود دارد اين است كه وقتي شما مشخص نكنين كه كدام ‍Constructor‌ از كلاس پدر فرخواني شود سازنده پيش فرض كلاس پدر فراخواني خواهد شد.

اما در صورتيكه نخواهيم سازنده پيش فرض فراخواني شود بايد چه كنيم؟ يا اگر در كلاس پدر سازنده پيش فرض نداشتيم چطور؟

در صورتيكه شما مي خواهيد يكي از سازنده هاي پدر را صراحا خودتان اعلام كنين كافي است كه در مقابل تعريف سازنده خود از كلمه base استفاده كنين:

public Customer(string Name, int Age, decimal Credit): base(Name,Age)
{
this.Credit = Credit;
Console.WriteLine("Customer Constructor called");
}

حالا اگر مجددا يك شيء از كلاس Customer ايجاد كنين , نتيجه اي متفاوت خواهيد داشت:



همانطور كه در تصوير خروجي هم مشخص است. ابتدا سازنده پدر فرخواني شده (كه البته با اين روش من كد كمتري هم نوشته ام و از كدي كه سازنده پدر وجود دارد استفاده مجدد كرده ام) و بعد سازنده كلاس Customer.

دانلود مثال اين پست

ادامه دارد...