تبلیغات
برق. قدرت. کنترل. الکترونیک. مخابرات. تاسیسات. - #c سی شارپ چیست؟3

برق. قدرت. کنترل. الکترونیک. مخابرات. تاسیسات.

دایره المعارف تاسیسات برق (اطلاعات عمومی برق)

Overriding in CSharp

همانطور که قبلا گفتم تمامی کلاس ها در سی شارپ چه بخواهند و چه نخواهند از کلاسی به نام object به ارث می روند و در نتیجه خصوصیات این کلاس به آن ها ارث می رسد. به عنوان مثال متد ToString که در تمامی کلاس هایی که ما ایجاد می کنیم وجود دارد و وقتی روی یک شیء متد ToString را فراخوانی می کنیم یک String از آن شیء در اختیار ما قرار می دهد که به صورت پیش فرض این رشته نام کامل کلاس شامل Namespace.Class می باشد.

1
2
3
4
5
6
7
Person p = new Person();
p.Name = "Ali";
p.Age = 20;
Console.WriteLine(p);
    // ConsoleApplication13.Person


در مثال بالا من یک شیء از کلاس Person ایجاد کرده و بعد از ست کردن نام و سن دستور چاپ آن شیء را از طریق متد WriteLine ارسال کرده ام. با توجه به اینکه متد WriteLine در موقع چاپ اشیاء به یک String نیاز دارد متد ToString را بر روی شیء من فراخوانی خواهد کرد. در نتیجه یک رشته از شیء من چاپ خواهد شد که نام کامل کلاس یعنی : ConsoleApplication13.Person می باشد.

به شکل زیر دقت کنین:



همانطور که می بینین متد ToString از کلاس پدر که کلاس object است به من به ارث رسیده است. اما رفتار این متد رفتاری نیست که من نیاز داشته باشم به این معنا که من نیاز دارم وقتی متد ToString را روی اشیایی از جنس کلاس Person (که من ایجاد کردم) فراخوانی می شود به جای نام کامل کلاس (Qualified Name) اطلاعات آن را (یعنی نام و سن) در اختیار من قرار دهد. به این معنی که می خواهم رفتارهای کلاس پدر را تغییر دهم که اصطلاحا به این کار Overriding می گویند.

برای اینکه من بتوانم رفتار کلاس پدر را تغییر دهم باید متد مورد نظرم را override کنم که این کار با استفاده از عبارت override و نوشتن مجدد متد با رفتار مورد نظر خودمون امکان پذیر می باشد:

1
2
3
4
5
6
7
8
9
10
11
12
public class Person
{
       public string Name;
       public int Age;
 
      <b>override</b> public string ToString()
      {
         return string.Format("Name:{0}, Age:{1}",Name,Age);
       }
}

بعد از نوشتن این تکه کد اگر دوباره کدی که در ابتدا نوشتیم را اجرا کنیم با رفتار جدید متد ToString که در واقع چاپ نام و سن می باشد مواجه خواهید شد.


Virtual Methods in CSharp

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


فرض بفرمائید که من یک کلاس به نام Person با دو Propertyی نام و سن و یک Method به نام Print که نام و سن را چاپ می کند ایجاد کرده ام. حالا می خواهم کاری کنم که کلاس هایی که از کلاس Person به ارث می روند بتوانند رفتار متد Print را override کنند. برای اینکه این امکان را در اختیار فرزندانم (کلاس هایی که از من به ارث می روند) قرار دهم باید در تعریف متد از عبارت virtual استفاده کنم. به کد کلاس Person دقت کنین:


1
2
3
4
5
6
7
8
9
10
public class Person
{
public string Name;
public int Age;
public virtual void Print()
{
Console.WriteLine("Name: {0}, Age: {1}", Name, Age);
}
}
1
2
 

حالا کلاس Emp را از کلاس Person به ارث می برم و یک فیلد جدید به نام Salary به آن اضافه می کنم و انتظار دارم که با override کردن متد Print کاری کنم که وقتی Print روی اشیایی از جنس Emp فراخوانی می شوند علاوه بر نام و سن , حقوق را نیز چاپ کند.

1
2
3
4
5
6
7
8
9
10
11
public class Emp : Person
{
               public decimal Salary;
 
               <b>override</b> public void Print()
               {
                  Console.WriteLine("Name:{0}, Age: {1}, Salary: {2}",Name,Age,Salary);
               }
}


با توجه به کد بالا در صورتیکه که این کد را برای تست بنویسم باید علاوه بر نام و سن , حقوق کارمند را هم چاپ نماید:

1
2
3
4
5
6
7
8
9
Emp e = new Emp();
e.Name = "Reza";
e.Age = 25;
e.Salary = 240000;
e.Print();
 
<b>                
</b>

!! نکته بسیار مهم در مورد Overriding این است که در صورتیکه Reference شما به یک شیء از جنس پدر نیز باشد , کامپایلر سی شارپ بدون توجه به نوع Reference به ماهیت شیء توجه کرده و متد مربوطه را چاپ می نمایند. به کد زیر دقت کنین:


1
2
3
4
5
6
7
8
9
10
11
Emp e = new Emp();
e.Name = "Saeid";
e.Age = 44;
e.Salary = 54000;
 
// در این خط از کد عملیات UpCast به سادگی انجام می شود
Person p = e;
// فراخوانی متدی که در کلاس پدر وجود داشته و در کلاس فرزند override شده است
p.Print();


با اینکه reference ما به شیء از جنس پدر(Person) می باشد ولی به دلیل override شدن در کلاس فرزند , پیاده سازی متد فرزند یعنی چاپ نام , سن و حقوق اجرا می شود.

چند ریختی در سی شارپ

بررسی مفهوم overriding را با یك مثال پیگیری می كنیم. یك سازمان یا شركت را در نظر بگیرید. این شركت دارای دو نوع كارمند می باشد. نوع اول كارمندان حقوق بگیری هستند كه حقوقشان را به صورت ماهیانه و با توجه به پایه حقوقی ثابتی كه برایشان در نظر گرفته شده است دریافت می كنند. به عنوان مثال "علی رضایی"‌ یك كارمند حقوق بگیر است كه برای هر ماه مبلغ "100,000" دریافت می كند.

نوع دوم كارمندانی هستند كه به صورت ساعتی حقوقشان را دریافت می كنند و برای هر ساعت كار یك مبلغ مشخصی دریافت می كنند. به عنوان مثال "رامین احمدی" یك كارمند ساعتی است كه برای هر ساعت كار مبلغ "3000" دریافت می كند.

در این مثال باتوجه به اینكه تمامی كارمندان دارای اطلاعات مشتركی هستند (مثل نام و شماره كارمندی و اطلاعات سوابق و ....)‌ تصمیم گرفتیم یك كلاس پایه به نام Emp كه مخفف Employee‌ است در نظر بگیریم و اطلاعات مشترك را در این كلاس تعریف كنیم:


همانطور كه می بینین با توجه به اینكه مفهوم حقوق برای كلاس كارمند (بدون مشخص بودن نوعش)‌ یك مفهوم انتزاعی است من در این مثال حقوق (یا همان Salary) را به صورت virtual‌ تعریف كرده ام , تا كلاس هایی كه از كلاس Emp به ارث می روند با override‌ كردن این Property‌ پیاده سازی درست آن را در نوع خود انجام دهند.


پس دو كلاس MonthlyEmp و HourlyEmp را كه از كلاس پایه Emp به ارث رفته اند به صورت زیر تعریف خواهند شد:

در كلاس MonthlyEmp‌ (كه در واقع كارمند حقوق بگیر ماهیانه می باشد) حقوق بر اساس "پایه حقوق" محاسبه می شود.



همانطور كه در كد می بینید , در كلاس HourlyEmp‌‌ (كه همان كارمند ساعتی است) حقوق براساس "مبلغ پایه هر ساعت" * "تعداد ساعات كاركرد" محاسبه و پرداخت و خواهد شد.


مثال را باید ایجاد یك كلاس چهارم به نام Company تكمیل می كنیم. در این كلاس یك آرایه از كارمند (Emp) داریم. دلیل اینكار كاملا آشكاراست. چون احتمال ایجاد كلاس های جدید (در واقع نوع های كارمندان جدید) وجود دارد در نتیجه من یك آرایه از كلاس پدر كه همان Emp‌ است برای نگهداری لیست كارمندان ایجاد می كنم.



همانطور كه در كد می بینین یك متد به نام PaySalary در این كلاس ایجاد شده كه در واقع هر ماه یكبار توسط مدیر عامل شركت جهت پرداخت حقوق تمامی كارمند استفاده می شود. صرف نظر از اینكه در موقع فراخوانی واقعا چه نوع كارمندی در این آرایه پر شده است , انتظار من این است كه اگر كارمند ساعتی بود از روش محاسبه كارمند ساعتی و اگر كارمند حقوق بگیر بود از روش محاسبه كارمند حقوق بگیر حقوق افراد پرداخت شود. این دقیقا همان نكته ایست كه در فقط در مواقعی كه شما از overriding‌استفاده كنین اتفاق خواهد افتاد. به عبارت دیگر "در overriding صرف نظر از نوع دیدگاه ما (reference) به یك شیء‌ , ماهیت آن مشخص كننده فراخوانی متد پدر یا فرزند خواهد بود" یعنی اگر حتی reference ما به یك شیء‌ MonthlyEmp‌ از نوع Emp‌ باشد (یعنی عمل upcase اعمال شده باشد) باز در مواقع فرخوانی متد , پیاده سازی فرزند مورد استفاده قرار خواهد گرفت. اصولا این عمل را در دنیای برنامه نویسی شیء‌گرا "چند ریختی" یا Polymorphysm‌ می گویند.



برای دریافت مثال كامل این پست می توانین از این لینك استفاده كنین:
بارگزاری مثال

Method Hiding in CSharp

پس بررسی مفهوم overriding‌ خوب است كه كمی در رابطه با مفهوم Hiding‌ هم صحبت كنیم. در واقعا Hiding‌ دوباره نویسی یك متد است كه قبلا در كلاس پدر نوشته شده. اما نكته ای كه وجود دارد این است كه در Hiding‌ كامپایلر سی شارپ با توجه به نوع Reference‌ شما متد را اجرا می كند.
اگر مثال آخرین پست را بررسی كنیم متوجه می شویم كه در آن مثال ما یك لیستی داشتیم از Emp ها (یك آرایه از Emp) كه در حقیقت اشیایی از MonthlyEmp‌ و HourlyEmp‌ را داخلشان قرار می دادیم. در واقع ما اشیایی از جنس كلاس های فزرند داشتیم اما به Reference‌هایی از جنس كلاس های پدر. نكته حائز اهمیت این است كه وقتی روی این اشیاء‌ متد ShowInfo‌ را فراخوانی می كردیم. با اینكه دید (Reference) ما به اشیاء‌ از نوع Emp بود ولی Salary را باتوجه به ماهیت اشیاء (چیزی كه با آن new‌شده بودند)‌فراخوانی می كرد و به نوع Reference‌ ما اهمیت نمی داد. با استفاده از همین خاصیت ما Polymorphism را در مثال قبل پیاده سازی كردیم.
Hiding در واقع نقطه مقابل Overriding است. به این ترتیب كه شما بدون توجه به ماهیت شیء (چیزی كه new شده است)‌و صرفا با توجه به نوع Reference پیاده سازی مربوطه را فرخوانی می كنین.

در مثال زیر من یك كلاس به نام Person‌ دارم كه متدی به نام Print را پیاده سازی كرده است.
یك كلاس دیگر به نام Student از كلاس Person‌ به ارث رفته و باز هم متد Print را پیاده سازی كرده است. دقت بفرمائید كه در Hiding هنگام پیاده سازی مجدد از كلمه كلیدی new استفاده خواهیم كرد.



پس در صورتیكه من یك شیء از جنس Student بسازم ولی دیدم را به Person‌ محدود كنم. وقتی متد Print را فراخوانی می كنم پیاده سازی كه در كلاس Person وجود دارد فراخوانی می شود. همانطور كه گفتیم در Hiding كامپایلر با توجه به Reference‌ ما متد مورد نظر را فراخوانی می كند و به ماهیت شیء توجهی نمی كند.



بارگزاری مثال Hiding

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div align="left">public class Person
{
public int Age;
public string Name;
 
public Person()
{
<b>Console.WriteLine("Default Constructor of Person Called");</b>
}
public Person(string Name, int Age)
{
this.Name = Name;
this.Age = Age;
<b>Console.WriteLine("2nd Constructor of Person Called");</b>
}
 
public virtual void Print()
{
Console.WriteLine("Name: {0}, Age: {1}", Name, Age);
}
}
</div>

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

حالا كلاس Customer‌ را از كلاس Person‌ به ارث می بریم:
1
2
3
4
5
6
7
8
9
10
<div align="left">public class Customer : Person
{
public decimal Credit;
 
override public void Print()
{
Console.WriteLine)"Name: {0}, Age: {1}, Credit: {2}", Name, Age, Credit);
}
}</div>

حالا برای تست یك شیء از كلاس Customer ایجاد می كنم:
1
2
3
4
5
6
7
<div align="left">Customer C = new Customer();
c.Name = "Ali";
c.Age = 20;
c.Credit = 2000;
c.Print();
</div>

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



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

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

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

در صورتیكه شما می خواهید یكی از سازنده های پدر را صراحا خودتان اعلام كنین كافی است كه در مقابل تعریف سازنده خود از كلمه base استفاده كنین:
1
2
3
4
5
6
7
<div align="left">public Customer(string Name, int Age, decimal Credit)<b>: base(Name,Age)
</b>{
this.Credit = Credit;
Console.WriteLine("Customer Constructor called");
}
</div>

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



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

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


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

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

1
2
3
int i = 10; int j = 20; int m = i * j / 2 + 14; Console.WriteLine("m is :{0}",m);
اما اگر شما عبارت زیر را بنویسید چطور؟

1
2
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 این کد را می نویسم:
1
2
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 را براساس نامشان قرار دهم از این کد استفاده می کنم:
1
2
public static bool operator ==(Person p1, Person p2) { return p1.Name == p2.Name; }
نکته مهم در این مثال این است که شما وقتی عملگر == (برابری) را دوباره نویسی می کنین باید عملگر != (نابرابری) را هم دوباره نویسی کنین:
1
2
public static bool operator !=(Person p1, Person p2) { return !(p1==p2); }

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

مثال برای overload کردن عملگرها
با اعداد کامپلکس که آشنا هستید ، a+bi که a, b عدد حقیقی هستند و i= جذر -1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Numbers
{
    public class ComplexNumber
    {
        double _Real = 0;
        double _Image = 0;
        public double Image
        {
            get { return _Real; }
            set { _Real = value; }
        }
        public double Real
        {
            get { return _Image; }
            set { _Image = value; }
        }
        public ComplexNumber()
        { }
        public ComplexNumber(double RealPart, double ImagePart)
        {
            Real = RealPart;
            Image = ImagePart;
        }
        public ComplexNumber(int RealPart, int ImagePart)
        {
            Real = (double)RealPart;
            Image = (double)ImagePart;
        }
        public override string ToString()
        {
            return string.Format("{0:G} + {1:G}i", _Real, _Image);
        }
        public static ComplexNumber operator +(ComplexNumber A, ComplexNumber B)
        {
            ComplexNumber c = new ComplexNumber();
            c.Real = A.Real + B.Real;
            c.Image = A.Image + B.Image;
            return c;
        }
        public static ComplexNumber operator -(ComplexNumber A, ComplexNumber B)
        {
            ComplexNumber c = new ComplexNumber();
            c.Real = A.Real - B.Real;
            c.Image = A.Image - B.Image;
            return c;
        }
        public static ComplexNumber operator *(ComplexNumber A, ComplexNumber B)
        {
            ComplexNumber c = new ComplexNumber();
            c.Real = (A.Real * B.Real) - (A.Image * B.Image);
            c.Image = (A.Image * B.Real) + (A.Real * B.Image);
            return c;
        }
        public static ComplexNumber operator /(ComplexNumber A, ComplexNumber B)
        {
            ComplexNumber c = new ComplexNumber();
            double s;
            s = B.Real * B.Real + B.Image * B.Image;
            c.Real = ((A.Real * B.Real) + (A.Image * B.Image)) / s;
            c.Image = ((A.Image * B.Real) - (A.Real * B.Image)) / s;
            return c;
        }
 
    }
}

و برای استفاده از این کلاس
1
2
3
4
5
6
ComplexNumber c1 = new ComplexNumber(1, 1);
            ComplexNumber c2 = new ComplexNumber(4d, 9d);
            MessageBox.Show((c1 + c2).ToString());
            MessageBox.Show((c1 - c2).ToString());
            MessageBox.Show((c1 * c2).ToString());
            MessageBox.Show((c1 / c2).ToString());
كنترل خطاها در سی شارپ - 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 مسیر اتقاقات رخ داده تا زمان بروز خطا را در غالب یک رشته داشته باشین:


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

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




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



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



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

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



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


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



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

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


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



Download Sample Code
وب سایت شخصی مسعود طباطبایی:
http://www.tabatabaei.info

مقالات من در رابطه با شیرپوینت:
Sharepoint Persian Calendar


کلاس های 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 ها

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 ها وجود ندارد.
در قسمت قبلی در رابطه با 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 as Service
وقتی بستر دات نت را بررسی می کنید به تعداد زیادی interface برخورد می کنید که وقتی آن ها را پیاده سازی کنید , می توانید از یک سرویس استفاده کنید. در واقع به ارث بری از یک اینترفیس شما یک از سرویس برخوردار خواهید شد.

به مثال زیر دقت کنید:



همانطور که در تصویر بالا مشخص است شما می توانید با استفاده از متد Sort روی کلاس ArrayList که در واقع یک Collection می باشد محتویات آرایه را سورت نمائید و در نتیجه خروجی شبیه به تصویر زیر داشته باشید:



حالا اگر در داخل یک ArrayList دیگر من چند شیء از جنس Person قرار دهم و باز متد Sort را فراخوانی کنم چه اتفاقی خواهد افتاد:



همانطور که در تصویر زیر می بینید به جهت اینکه فریم ورک دات نت نمی داند که باید سورت را بر چه مبنایی روی تایپ های custom مثل Person انجام دهد یک Exception (خطا) پرتاب خواهد شد.



در واقع در فریم ورک دات نت هرکجا شما به سورت کردن یک تایپ خاص مثل Person را نیاز داشتید کافیست که از یک Interface به نام IComparable به ارث برید. یا به بیانی دیگر مایکروسافت سرویس Sort را در غالب این اینترفیس ارائه می کند. حالا به کد زیر که پیاده سازی اینترفیس IComparable می باشد دقت کنید:



همانطور که می بینید در داخل این اینترفیس یک متد به نام CompareTo وجود دارد که یک ورودی از جنس Object دارد و یک خروجی عددی. در صورتیکه عددی که از این متد خارج می شود بزرگتر از یک باشد به این معناست که شیء جاری(this) بزرگتر از پارامتر پاس شده می باشد و در صورتیکه عدد کوچکتر از صفر باشد به این معناست که شیء جاری کوچکتر از پارامتر پاس شده می باشد و اگر این دو باهم برابر باشد باید خروجی متد 0 باشد. در کدی که من نوشتم مبنای مقایسه را برروی سن افراد قرار دادم که در نتیجه این نوع پیاده سازی خروجی زیر از نمونه کد بالا حاصل خواهد شد:



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


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



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

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



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



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

بارگزاری مثال
اینترفیس برای توارث چندگانه - Interface for Multiple Inheritance
در پاره ای از مواقع , به این نتیجه می رسیم که یک موجودیت در نرم افزار شما باید از دو یا چند موجودیت دیگر به ارث برود. اما همانطور که قبلا هم اشاره کرده بودم در سی شارپ توارث چندگانه وجود ندارد پس شما نمی توانید از چند کلاس همزمان به ارث بروید. راه حل این سناریو ها استفاده از اینترفیس ها برای پیاده سازی توارث چندگانه می باشد. نکته ای که وجود دارد این است که استفاده از این روش باعث کم تر شدن کد نویسی شما نخواهد شد.

فرض بفرمائید که در طراحی یک سیستم برای یک شرکت تولید دو موجودیت "مشتری" و "کارمند" طراحی شده اند. هر مشتری دارای اطلاعاتی نظیر نام و مبلغ اعتبار و یک متد برای خرید و یک متد برای نمایش اطلاعاتش می باشد. هر کارمند نیز دارای اطلاعاتی نظیر نام و حقوق و یک متد برای نمایش اطلاعاتش می باشد. حالا شما به این نتیجه رسیده اید که یکسری از کارمندان شرکت از شرکت خرید نیز انجام می دهند یعنی در واقع مشتری هم هستند. به همین دلیل تصمیم گرفته اید که یک کلاس به نام EmpCustomer ایجاد کنید که هم از مشتری به ارث رفته باشد و هم از کارمند.

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

پیاده سازی توارث چندگانه با استفاده از اینترفیس ها

همانطور که قبلا اشاره کردیم یک کلاس توانایی به ارث رفتن از یک کلاس و چندین اینترفیس را دارا می باشد. برای همین منظور من دو اینترفیس به نام های ICustomer و IEmployee ایجاد می کنم:



سپس دو کلاس خود یعنی Employee و Customer را از اینترفیس های متناظرشان به ارث می برم و پیاده سازی می کنم:






حالا کافیست کلاس سوم را از ایجاد و از هر دو این اینترفیس ها به ارث می بریم:



همین طور که در تصویر می بینید در Print به جای عبارت Employee یا Customer عبارت EmpCustomer چاپ خواهد شد.

!! در این روش قصد ما اصلا کمتر نوشتن کد نمی باشد بلکه فقط پیاده سازی توارث چندگانه می باشد.

!! توجه داشته باشید که وقتی یک کلاس از دو یا چند اینترفیس به ارث می رود که دارای اطلاعات مشترکی هستند (مثل Name و Print در این مثال) یکبار پیاده سازی آن کافی است.

حالا کلاس Company را ایجاد می کنم و به جای اینکه یک آرایه از جنس Customer برای مشتریان و یک آرایه از جنس Employee برای کارمندان در نظر بگیرم آرایه ای از ICustomer برای مشتریان و آرایه ای از IEmployee برای کارمندان در نظر خواهم گرفت.



همانطور که در تصویر بالا مشاهده می کنید یک متد برای درج مشتریان به نام AddCustomer در نظر گرفته ام و نوع ورودی آن را از جنس ICustomer در نظر گرفته ام. همین روش برای متد AddEmployee هم با IEmployee انجام داده ام. در نتیجه شما می توانید اشیایی از جنس Employee و EmpCustomer را در لیست کارمندان و اشیایی از جنس Customer و EmpCustomer را در لیست مشتریان قرار دهید.

در مثال قبلی با پیاده سازی کلاس EmpCustomer به مقصود خود رسیدیم و در واقع می توانستیم که اشیایی از این نوع را هم به ICustomer و هم به IEmployee نسبت دهیم. حالا به کد زیر دقت کنید:




همانطور که می بینید من 3 شیء جدید ایجاد کرده ام. 2 تا Employee و یک EmpCustomer و آنها را به عنوان کارمند در لیست کارمندان شرکت اضافه نموده ام. و همینطور 2 شیء دیگر که از نوع Customer هستند. و به همراه شیء قبلی که از جنس EmpCustomer بود به لیست مشتریان شرکت اضافه کرده ام. حالا اگر از شیء شرکت متد های چاپ لیست مشتریان و چاپ لیست کارمندان را فراخوانی کنم نتیجه زیر را خواهیم دید.



این نتیجه در واقع نتیجه درستی است چرا که من 3 مشتری و 3 کارمند دارم. اما نکته ای که وجود دارد این است که شیء EmpCustomer من در موقع نمایش اطلاعات خود ، با ما بقی اشیاء من متفاوت است. یعنی وقتی در لیست کارمندان نمایش داده می شود تفاوت آن با بقیه کارمند و در لیست مشتریان با بقیه مشتریان مشهود است. اما من می خواهم که در هر دو حالت کاملا شبیه به این دو نوع باشد و رفتاری مشابه بقیه داشته باشد. در نتیجه من باید از Explicit Interface Implementation استفاده کنم.

Explicit Interface Implementation
این روش موقعی استفاده می شود که شما می خواهید رفتار یک شیء را بسته به نوع reference آن تعیین کنید. یعنی وقتی به یک شیء از جنس EmpCustomer از دیدگاه ICustomer نگاه می کنید رفتاری شبیه مابقی ICustomer ها داشته باشد و وقتی از دید IEmployee نگاه می کنید رفتاری شبیه به مابقی IEmployee ها داشته باشد و در حالتی که از دید EmpCustomer نگاه می کنید رفتار خاص دیگر داشت باشد. در مثال ما شما باید متد Print را سه مرتبه پیاده سازی کنید. به این کد دقت کنید:



همانطور که می بینید در پیاده سازی های دوم و سوم ابتدا نام interface و سپس دقیقا اسم متد را به همان ترتیب که در interface ها نوشته شده است و بدون access modifier می نویسیم. در پیاده سازی متد نیز کاملا شبیه به Employee و Customer عمل خواهیم کرد. در نتیجه اگر مثال قبلی را دوباره اجرا کنید خروجی به شکل زیر خواهید داشت.



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

صفحات جانبی

نظرسنجی

    لطفاً نظرات خود را درمورد وبلاگ با اینجانب در میان بگذارید.(iman.sariri@yahoo.com)نتایج تاکنون15000مفید و 125غیرمفید. با سپاس


  • آخرین پستها

آمار وبلاگ

  • کل بازدید :
  • تعداد نویسندگان :
  • تعداد کل پست ها :
  • آخرین بازدید :
  • آخرین بروز رسانی :