ایران سرفراز- نرم افزار وپروژهای دانشجویی


نرم افزار وپروژهای دانشجویی

فصل هفتم متدهای داخلی در# C

<!-- /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman";} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0;} div.Section1 {page:Section1;} -->

فصل هفتم Mohsen_mahyar@yahoo.com

    

C# متدهای داخلی در

آنچه که در این فصل یاد خواهید گرفت:

کردن متدها و استفاده از آنها overload • روش

استفاده از خصوصیات برای کپسولهکردن اطلاعات یک شی

و نقش آنها در ارسال دادهها به متدها ref و out • کار با پارامترهای

برای دسترسی یا مقداردهی به خصوصیات کلاسها set و get • معاونهای

در فصلهای قبل دیدیم که کلاسها شامل فیلدها و متدهایی هستند. فیلدها حالت شی را نشان میدهند و متدها رفتار شی

را تعریف میکنند.

کردن overload نحوه کار متدها را دقیق کاوش خواهید کرد. تابحال نحوهی ایجاد متد را دیده اید. شما _ شما در این فصل

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

احضار متد با انواع پارامتر مختلف قادر میسازد.

این فصل خصوصیات را معرفی میکند. خصوصیات شبیه متغیرهای عضو هستند، اما خصوصیات همچون متدها پیادهسازی

میشوند. این عمل پنهانکردن دادهها 1 را به نحو خوب ادامه میدهد.

کردن متدها overload-1-7

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

ایجاد میکنید. Time به شما اجازه میدهد اشیاء را با انواع مختلف پارامترها ایجاد کنید. برای مثال، اگر شما یک شی

ممکن است بخواهید یک شی _ ساعت ایجاد کنید. مواقعی دیگر _ را با ارسال تاریخ Time احتمال دارد بخواهید شی

کردن سازنده، این گزینههای متعدد را فراهم میسازد. overLoad . را با ارسال یک شی موجود ایجاد کنید Time

1 Information hiding

فصل هفتم- متدهای داخلی

121

را دارد. مناسب Time که تعداد زیادی از عضوهای دادهای کلاس _ است System یک شی درونی کتابخانه DateTime شی

دقیقه و ثانیه به آن ایجاد _ ساعت _ روز _ ماه _ جدید را با ارسال سال Time است که سرویسگیرنده مجاز باشد یک شئ

کند. بعضی سرویسگیرندهها یک یا چند سازنده را ترجیح میدهند.

باید مطمئن باشید که هر سازنده نشانهی منحصربهفردی دارد. نشانهی یک متد از نام _ کردن سازنده overload به منظور

و لیست پارامترهایش تشکیل شده است. اگر دو متد نام یا لیست پارامتر مختلفی داشته باشند. نشانههای مختلفی دارند.

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

نشانه آنها متمایز کنیم.

void MyMethod(int p١);

void MyMethod(int p١, int p٢); // different number

void MyMethod(int p١, string s١); // different types

void SomeMethod(int p١); // different name

هستند. دو مورد اولی ازنظر تعداد پارامترها متفاوت هستند و متد دوم ()MyMethod های متد overload سه متد اول همه

و سوم در نوع پارامتر دوم با هم متفاوت هستند. این تغییرات در نشانه متدها کافی است تا کامپایلر متدها را متمایز کند.

نیست، فقط یک متد متفاوتی است. یک کلاس میتواند هر تعداد overload متد چهارم با بقیه از نظر نام فرق میکند، این

را با دو سازنده نشان میدهد. یکی از آن متدها یک شی Time 1 کلاس - متد با نشانههای مختلف داشته باشد. مثال 7

را میگیرد و دیگری 6 عدد صحیح میگیرد. DateTime

1- مثال 7

using System;

namespace MethodOverloading

{

public class Time

{

// private member variables

private int Year;

private int Month;

private int Date;

private int Hour;

private int Minute;

private int Second;

// public accessor methods

public void DisplayCurrentTime( )

{

System.Console.WriteLine( "{٠}/{١}/{٢} {٣}:{۴}:{۵}",Month, Date, Year, Hour,

Minute, Second );

}

// constructors

public Time( System.DateTime dt )

{

Year = dt.Year;

Month = dt.Month;

Date = dt.Day;

Hour = dt.Hour;

Minute = dt.Minute;

Second = dt.Second;

}

int Hour, int Minute, int Second )

{

this.Year = Year;

this.Month = Month;

this.Date = Date;

this.Hour = Hour;

this.Minute = Minute;

this.Second = Second;

#C برنامه نویسی

122

}

}

class Tester

{

public void Run( )

{

System.DateTime currentTime = System.DateTime.Now;

Time time١ = new Time( currentTime );

time١.DisplayCurrentTime( );

Time time٢ = new Time( ٢٠٠٠, ١١, ١٨, ١١, ٠٣, ٣٠ );

time٢.DisplayCurrentTime( );

}

static void Main( )

{

Tester t = new Tester( );

t.Run( );

}

}

}

خروجی شبیه زیر است:

٧/١٠/٢٠٠٨ ١۶:١٧:٣٢

١١/١٨/٢٠٠٠ ١١:٣:٣٠

بشناسد. با این Time کامپایلر نمیتواند سازندهها را هنگام ایجاد اشیاء جدید _ اگر نشانهی یک تابع فقط نام آن باشد

چون نشانهی متد پارامترها و نوع دادههای آنها را شامل است، کامپایلر قادر است هر سازنده را با نشانه مورد نظر _ وجود

تطابق دهد.

System.DateTime currentTime = System.DateTime.Now;

Time time١ = new Time(currentTime);

public Time(System.DateTime dt)

2 سازندهای که نشانهی آن 6 آرگومان صحیح میگیرد را فراخوانی کند. time همچنین کامپایلر قادر است برای

Time time٢ = new Time(٢٠٠٠،١١،١٨،١١،٠٣،٣٠);

public Time(int Year, int Month, int Date, int Hour, int Minute, int Second)

میکنید، باید نشانه آن را تغییر دهید. در تغییر نوع داده بازگشتی آزاد هستید، چون overload زمانی که یک متد را

نمیکند. دو متد که نشانه یکسان دارند و نوع بازگشتی آن متفاوت باشد یک خطای کامپایلر overload تغییرات آن متد را

تولید میکنند.

-2-7 کپسوله کردن دادهها با خصوصیات

پسندیده است. بدین معنی که فقط متدهای عضو کلاس private در کل، طراحی متغیرهای عضو یک کلاس بصورت

میتوانند به مقادیر آنها دستیابی کنند. زمانی که از دستیابی مستقیم به متغیرهای عضو یک کلاس جلوگیری میکنید، پنهان

کردن دادهها را با اجبار اعمال میکنید که بخشی از کپسوله سازی یک کلاس است.

باشند. این عمل خوب است، اما چگونه دسترسی به دادهها را private برنامهنویسان شیگرا میگویند متغیرهای عضو باید

کاربرد خصوصیات است. #C برای سرویسگیرنده ها فراهم کنیم. جواب برنامه نویسان

خصوصیات دسترسی به حالت کلاس را بدون دسترسی مستقیم به فیلدها اجازه میدهند و پیادهسازی خصوصیات شبیه

متدها انجام میشود. این راهحل ایدهآل است. سرویسگیرنده دسترسی مستقیم به حالت شی را میخواهد. طراح کلاس

میخواهد حالت داخلی کلاس را در فیلدهای کلاس پنهان کند و دسترسی غیر مستقیم را از طریق یک متد فراهم میکند.

با جدا کردن حالت کلاس از متدهایی که به حالت کلاس دسترسی دارند، طراح کلاس برای تغییر حالت داخلی کلاس در حد

به عنوان یک متغیر عضو ذخیره میشد. Hour برای اولین بار ایجاد شد، احتمالا مقدار Time نیاز آزاد است. زمانی که کلاس

فصل هفتم- متدهای داخلی

123

محاسبه یا از پایگاهداده بازیابی شود. اگر سرویسگیرنده Hour زمانی که کلاس مجددا طراحی میشود، ممکن است مقدار

سرویسگیرنده را با شکست مواجه _ داشته باشد، تغییر دادن نحوهی حل مسئله Hour دسترسی مستقیم به متغیر عضو

خواهد کرد.

2 یک خصوصیت بنام - ویژگی پنهانسازی داده مورد نیاز، طراحی شیگرای خوب را فراهم میکند. مثال 7 _ بطور خلاصه

ایجاد میکند که در پاراگرافهای زیر بحث میشود. Hour

using System;

namespace Properties

{

public class Time

{

// private member variables

private int year;

private int month;

private int date;

private int hour;

private int minute;

private int second;

// create a property

public int Hour

{

get

{

return hour;

}

set

{

hour = value;

}

}

// public accessor methods

public void DisplayCurrentTime( )

{

System.Console.WriteLine("Time: {٠}/{١}/{٢} {٣}:{۴}:{۵}",month, date, year, hour,

minute, second );

}

// constructors

public Time( System.DateTime dt )

{

year = dt.Year;

month = dt.Month;

date = dt.Day;

hour = dt.Hour;

minute = dt.Minute;

second = dt.Second;

}

}

class Tester

{

public void Run( )

{

System.DateTime currentTime = System.DateTime.Now;

Time t = new Time( currentTime );

t.DisplayCurrentTime( );

// access the hour to a local variable

int theHour = t.Hour;

// display it

System.Console.WriteLine( "Retrieved the hour: {٠}",theHour );

// increment it

theHour++;

// reassign the incremented value back through

#C برنامه نویسی

124

// the property

t.Hour = theHour;

// display the property

System.Console.WriteLine( "Updated the hour: {٠}", t.Hour);

}

[STAThread]

static void Main( )

{

Tester t = new Tester( );

t.Run( );

}

}

}

خروجی باید چیزی شبیه این باشد :

Time : ٧/١٠/٢٠٠٨ ١٢:٧:۴٣

Retrieved the hour: ١٢

Updated the hour: ١٣

1 set یک خصوصیت را با نوشتن نوع و نام آن که با {} دنبال میشود، تعریف کنید. در داخل آکولادها میتوانید معاونهای

را اعلان کنید. این معاونها خیلی شبیه متدها هستند، اما در واقع بخشی از خصوصیت هستند. هدف این معاونها get و

فراهمسازی یک راه ساده برای بازیابی یا تغییر مقدار عضو خصوصی کلاس است.

دارد که برای value یک پارامتر ضمنی بنام set هیچ کدام یک از این معاونها پارامترهای صریح ندارند اگرچه معاون

تنظیم مقدار متغیر عضو استفاده میشود.

اسامی خصوصیتها با علائم پاسکال نوشته میشوند. _ طبق قرارداد

را ایجاد میکند. set و get دو معاون Hour 2 اعلان خصوصیت - در مثال 7

{

get

{

return hour;

}

set

{

hour = value;

}

}

هر معاون یک بدنه دارد که کار بازیابی یا تنظیم مقدار خصوصیت را انجام میدهد. ممکن است مقدار خصوصیت در یک

پایگاهداده ذخیره شود یا اینکه در یک متغیر عضو خصوصی ذخیره شود.

private int hour;

get -1 معاون -2-7

Hour 2 معاون خصوصیت - شبیه متدی است که یک شی از نوع خصوصیت را برمیگرداند. در مثال 7 get بدنهی معاون

را بر میگرداند. hour برمیگرداند. آن مقدار متغیر عضو خصوصی int شبیه متدی است که یک مقدار

get

{

return hour;

}

1 Accessor

فصل هفتم- متدهای داخلی

125

Hour احضار میشود. به عنوان مثال در کد زیر مقدار خصوصیت get هر زمان به بازیابی مقدار خصوصیت نیاز است، معاون

Hour به مقدار خصوصیت theHour به یک متغیر محلی انتساب داده میشود. در سرویسگیرنده، متغیر محلی Time شی

انتساب داده میشود. t شی

Time t = new Time(currentTime);

int theHour = t.Hour;

set -2 معاون -2-7

را برای نمایش value باید کلمهی کلیدی set یک خصوصیت را مقداردهی میکند. زمان تعریف یک معاون set معاون

آرگومان ضمنی بکار برید. که این مقدار به خصوصیت انتساب داده میشود.

set

{

hour = value;

}

میتواند آنرا به یک set مجددا در اینجا یک متغیر عضو خصوصی برای ذخیره مقدار خصوصیت استفاده میشود. اما معاون

پایگاه داده بنویسد یا متغیرهای عضو دیگر مورد نیاز را بروز کند. زمانیکه یک مقدار به خصوصیت انتساب میکنید، معاون

بطور اتوماتیک احضار میشود و مقدار پارامتر ضمنی با مقدار مورد نظر شما مقداردهی میشود. set

theHour++;

t.Hour = theHour;

انتساب داده میشود. در t شی Hour را افزایش میدهد. مقدار جدید به خصوصیت theHour خط اول مقدار متغیر محلی

hour ارسال میشود تا آن را به متغیر عضو محلی set به معاون value به عنوان پارامتر ضمنی theHour واقع مقدار

منتسب کند.

یک _ خصوصیت ایجاد کنید. بطور مشابه set می توانید خصوصیت فقط خواندنی را با عدم سازی بخش

ایجاد کنید. get خصوصیت فقط نوشتنی را با عدم پیادهسازی بخش

-3-7 برگرداندن چندین مقدار

برگردید. شاید ایجاد Time متدها فقط میتوانند یک مقدار برگردانند، اما این همواره مناسب نیست. به کلاس

برای برگرداندن ساعت، دقیقه و ثانیه کار بزرگی باشد. شما نمیتوانید هر سه مقدار را برگردانید، اما ()GetTime متد

پارامترها را تغییر دهد و نتیجهی آنها را بززسی ()GetTime میتوانید در سه پارامتر آنها را ارسال کنید. اجازه دهید متد

3 اولین تلاش است. - کنید. مثال 7

3- مثال 7

using System;

namespace PassByRef

{

public class Time

{

// private member variables

private int Year;

private int Month;

private int Date;

private int Hour;

private int Minute;

private int Second;

// public accessor methods

public void DisplayCurrentTime()

#C برنامه نویسی

126

{

System.Console.WriteLine( "{٠}/{١}/{٢} {٣}:{۴}:{۵}",Month, Date, Year, Hour,

Minute, Second );

}

public void GetTime(int theHour,int theMinute,int theSecond )

{

theHour = Hour;

theMinute = Minute;

theSecond = Second;

}

// constructor

public Time( System.DateTime dt )

{

Year = dt.Year;

Month = dt.Month;

Date = dt.Day;

Hour = dt.Hour;

Minute = dt.Minute;

Second = dt.Second;

}

}

class Tester

{

public void Run()

{

System.DateTime currentTime = System.DateTime.Now;

Time t = new Time( currentTime );

t.DisplayCurrentTime();

int theHour = ٠;

int theMinute = ٠;

int theSecond = ٠;

t.GetTime( theHour, theMinute, theSecond );

System.Console.WriteLine( "Current time: {٠}:{١}:{٢}",theHour, theMinute,

theSecond);

}

static void Main()

{

Tester t = new Tester();

t.Run();

}

}

}

خروجی چیزی شبیه این است :

٧/١/٢٠٠٨ ١٢:٢٢:١٩

Current time: ٠:٠:٠

تلاش اول کارساز نیست. مشکل در پارامترها است. شما سه _ توجه کنید که زمان جاری در خروجی 0:0:0 است. بطور واضح

را تغییر دادید و آنها در برگشت بدون تغییر بودند، ()GetTime ارسال کردید و پارامترهای ()GetTime پارامتر صحیح را به

چون این پارامترها از نوع دادهی مقداری هستند.

-1 ارسال انواع دادهی مقداری بوسیله ارجاع -3-7

یک کپی از آن مقدار ایجاد میشود. زمانی که پارامتر را تغییر _ زمانی که یک نوع دادهی مقداری به متد ارسال میکنید

تحت تاثیر ()GetTime متغیرهای صحیح اصلی توسط تغییرات متد ()Run میدهید، در اصل کپی را تغییر دادهاید. در متد

قرار نگرفتهاند.

فصل هفتم- متدهای داخلی

127

آنچه شما نیاز دارید، ارسال پارامترهای صحیح بوسیله ارجاع است. تا تغییرات ایجاد شده در متد به شی اصلی فراخوانی متد

اعمال گردد. زمانی که یک شی را با ارجاع ارسال میکنید، پارامتر به همان شی اشاره میکند. پس زمانی که در پارامترهای

اعمال میگردد. ()Run تغییراتی ایجاد میکنید، این تغییرات به متغیرهای اصلی در ()GetTime

را طوری تغییر دهید که پارامترها را بصورت ()GetTime 3 لازم است. ابتدا پارامترهای متد - دو تغییر کوچک درمثال 7

نشان دهد. ref پارامترهای

public void GetTime(ref int theHour,ref int theMinute,ref int theSecond )

{

theHour = Hour;

theMinute = Minute;

theSecond = Second;

}

برای ارسال آرگومانها به صورت ارجاع ها است. ()GetTime تغییر دوم فراخوانی متد

t.GetTime(ref theHour, ref theMinute, ref theSecond);

تبدیل کند. ref int را به int کامپایلر هشدار میدهد که نمیتواند _ اگر شما مرحله دوم را انجام ندهید

4 نشان داده میشود. - این تغییرات در مثال 7

4- مثال 7

using System;

namespace PassByRef

{

public class Time

{

// private member variables

private int Year;

private int Month;

private int Date;

private int Hour;

private int Minute;

private int Second;

// public accessor methods

public void DisplayCurrentTime()

{

System.Console.WriteLine( "{٠}/{١}/{٢} {٣}:{۴}:{۵}",Month, Date, Year, Hour,

Minute, Second );

}

// takes references to ints

public void GetTime(int theHour,int theMinute,int theSecond )

{

theHour = Hour;

theMinute = Minute;

theSecond = Second;

}

// constructor

public Time( System.DateTime dt )

{

Year = dt.Year;

Month = dt.Month;

Date = dt.Day;

Hour = dt.Hour;

Minute = dt.Minute;

Second = dt.Second;

}

}

class Tester

{

public void Run()

#C برنامه نویسی

128

{

System.DateTime currentTime = System.DateTime.Now;

Time t = new Time( currentTime );

t.DisplayCurrentTime();

int theHour = ٠;

int theMinute = ٠;

int theSecond = ٠;

// pass the ints by reference

t.GetTime( ref theHour, ref theMinute, ref theSecond );

System.Console.WriteLine( "Current time: {٠}:{١}:{٢}",theHour, theMinute,

theSecond );

}

static void Main()

{

Tester t = new Tester();

t.Run();

}

}

}

حال خروجی شبیه زیر است :

٧/١/٢٠٠٨ ١٢:٢۵:۴١

Current time: ١٢:٢۵:۴١

حال نتایج حاصله زمان درست را نشان میدهند.

کامپایلر را راهنمایی کردید تا آنها را با ارجاع ارسال کند. بخاطر داشته باشید که ref با اعلان این پارامترها بصورت

ارجاعاتی به مقدار اصلی خود هستند. ref پارامترهای

و انتساب روشن 1 out -2 پارامترهای -3-7

قبل از _ 4 - انتساب روشن را تحمیل میکند، یعنی لازم است همه متغیرها قبل از استفاده مقداردهی شوند. در مثال 7 #C

آنها را مقداردهی اولیه کردید. ()GetTime ارسال پارامترها به

int theHour = ٠;

int theMinute = ٠;

int theSecond = ٠;

t.GetTime( ref theHour, ref theMinute, ref theSecond);

ارسال میشوند که در آنجا تغییر ()GetTime مقداردهی اولیه این متغیرها نامعقول است، چون فورا بوسیله ارجاع به

خواهند یافت. اما اگر این کار را انجام ندهید، خطاهای کامپایل زیر گزارش میشوند.

Use of unassigned local variable 'theHour'

Use of unassigned local variable 'theMinute'

Use of unassigned local variable 'theSecond'

ضرورت مقداردهی اولیه یک پارامتر ارجاعی را #C را برای این چنین موقعیتها فراهم کرده است. این معرف out معرف #C

هیچ اطلاعاتی برای متد آماده نمیکنند. بطور ساده آنها یک مکانیزم برای ()GetMethod حذف میکند. پارامترهای متد

ضرورت مقداردهی اولیه آنها را در خارج از متد حذف ،out گرفتن اطلاعات هستند. پس علامتگذاری آنها با کلمه کلیدی

یک مقدار انتساب داده شود. اعلان out میکند. در متد فراخوانده شده قبل از بازگشت متد، باید به پارامترهای

بصورت زیر تغییر مییابد. ()GetTime

public void GetTime(out int theHour,out int theMinute,out int theSecond )

{

theHour = Hour;

theMinute = Minute;

1 Definite assignment

فصل هفتم- متدهای داخلی

129

theSecond = Second;

}

بصورت زیر است. ()Main احضار جدید متد در

int theHour;

int theMinute;

int theSecond;

t.GetTime( out theHour, out theMinute, out theSecond);

اجازه میدهد پارامترهای موجود در فراخوانی متد out را میرساند، به استثناء اینکه ref همان مفهوم out کلمه ی کلیدی

بدون مقداردهی اولیه استفاده شوند.

-4-7 خلاصه

کردن همان عمل ایجاد دو یا چند متد هم نام است که تعداد و یا نوع پارامترهای آنها متفاوت است. overload •

اما برای طراح خصوصیات شبیه متدها هستند. طراح به کمک _ خصوصیات شبیه اعضا هستند _ • برای سرویسگیرنده

خصوصیات میتواند نحوهی بازیابی مقدار خصوصیت را بدون شکستن مفهوم برنامه سرویسگیرنده تغییر دهد.

یک پارامتر ضمنی بنام set را برای بازیابی یا تغییر یک فیلد بکار میبرند. معاون set و get • خصوصیات معاونهای

دارد که مقدار جدید از طریق آن به خصوصیت انتساب داده میشود. value

تغییرات داخل متد به شی اصلی در فراخوانی متد اعمال _ • زمانی که یک پارامتر را بوسیله ارجاع به متد ارسال میکنید

میتوانید بصورت ارجاعی ارسال کنید. out و ref میگردد. انواع دادهی مقداری را بوسیله

ضرورت مقداردهی اولیه یک متغیر را قبل از ارسال آن به متد حذف میکند. out • پارامتر

Mohsen_mahyar@yahoo.com

 

   + MOHSEN GHASEMI - ۸:٤٢ ‎ق.ظ ; ۱۳۸٩/٤/٦