درس پنجم – متدها

 

در اين قسمت با متدها در زبان C# آشنا مي‌شويد. اهداف اين درس به شرح زير مي‌باشد :

ü      درك ساختار يك متد

ü      درك تفاوت بين متدهاي استاتيك (static methods) و متدهاي نمونه (instance)

ü     ايجاد نمونه جديد از اشياء

ü      نحوه فراخواني متدها

ü      درك چهار گونه متفاوت پارامترها

ü      نحوه استفاده از مرجع this

 

تا كنون تمامي اعمالي كه ما در برنامه‌هايمان انجام مي‌داديم در متد Main() اتفاق مي‌افتادند. اين روش براي برنامه‌هاي ساده و ابتدايي كه استفاده كرديم مناسب بود، اما اگر برنامه‌ها پيچيده‌تر شوند و تعداد كارهاي مورد نظر ما گسترش يابد، استفاده از متدها جايگزين روش قبل مي‌گردد. متدها فوق‌العاده مفيد هستند، چراكه كارها را به بخشهاي كوچكتر و مجزا تقيسم مي‌كنند و در نتيجه استفاده از آنها آسان‌تر خواهد بود.

ساختار كلي يك متد به صورت زير است :

[attributes][ modifiers] return-type method-name ([ parameters] ) { statements }

 

دو قسمت attributes و modifiers را در آينده مورد بررسي قرار خواهيم داد. return-type نوعي است يك متد باز مي‌گرداند و مي‌تواند هر يك از انواع تعريف شده زبان  C# و يا از انواع تعريف شده توسط كاربر باشد. هر متد با نام آن شناخته مي‌شود. method-name نام انتخابي برنامه‌نويس براي يك متد است و از طريق همين نام فراخواني متد انجام مي‌شود. پارامترها (parameters) مولفه‌ها يا متغيرهايي هستند كه براي انجام يكسري پردازش به متد ارسال مي‌شوند و از طريق آنها مي‌توان اطلاعاتي را به متد ارسال و يا از آن دريافت نمود، و در نهايت دستورالعمهاي متد، دستورهايي از زبان C# هستند كه بوسيله آنها عمل مورد نظر برنامه‌نويس انجام مي‌شود و عملي است كه يك متد آنرا انجام مي‌دهد. مثال 1-5 پياده‌سازي يك متد ساده را نمايش مي‌دهد.

using System;

 

class OneMethod

{

  public static void Main()

   {

     string myChoice;

     OneMethod om = new OneMethod();

     do

      {

       myChoice = om.getChoice();

       // تصميمي بر اساس انتخاب كاربر گرفته مي‌شود

       switch(myChoice)

        {

          case "A":

          case "a":

          Console.WriteLine("You wish to add an address.");

               break;

          case "D":

          case "d":

          Console.WriteLine("You wish to delete an address.");

               break;

          case "M":

          case "m":

          Console.WriteLine("You wish to modify an address.");

               break;

          case "V":

          case "v":

          Console.WriteLine("You wish to view the address list.");

               break;

          case "Q":

          case "q":

          Console.WriteLine("Bye.");

               break;

          default:

             Console.WriteLine("{0} is not a valid choice", myChoice);

          break;

        }

      // اجراي برنامه براي ديدن نتايج موقف مي‌شود

      Console.WriteLine();

      Console.Write("Press Enter key to continue...");

      Console.ReadLine();

      Console.WriteLine();

     } while (myChoice != "Q" && myChoice != "q");

     // اجراي برنامه تا زمانيكه كاربر بخواهد ادامه مي‌يابد

   }

  string getChoice()

   {

     string myChoice;

     // منويي را نمايش مي‌دهد

     Console.WriteLine("My Address Book\n");

     Console.WriteLine("A - Add New Address");

     Console.WriteLine("D - Delete Address");

     Console.WriteLine("M - Modify Address");

     Console.WriteLine("V - View Addresses");

     Console.WriteLine("Q - Quit\n");

     Console.Write("Choice (A,D,M,V,or Q): ");

     // ورودي دريافتي از كاربر را بررسي مي‌كند

     myChoice = Console.ReadLine();

     Console.WriteLine();

     return myChoice;

   }

}

 

برنامه مثال 1-5 دقيقا همان برنامه در س 4 است، با اين تفاوت كه در درس چهارم چاپ منو و دريافت ورودي از كاربر در متد Main() صورت مي‌گرفت در حاليكه در اين مثال،‌ اين اعمال در يك متد مجزا بنام getChoice() صورت مي‌گيرد. نوع بازگشتي اين متد از نوع رشته‌اي است. از اين رشته در دستور switch در متد Main() استفاده مي‌شود. همانطور كه ملاحظه مي‌نماييد، پرانتزهاي متد getChoice() خالي هستند، يعني اين متد داراي پارامتر نيست، از اينرو هيچ اطلاعاتي به/ از اين متد منتقل نمي‌شود.

 

درون اين متد، ابتدا متغير myChoice را اعلان نموده‌ايم. هرچند نام و نوع اين متغير همانند متغير myChoice موجود در متد Main() است، اما اين دو متغير دو متغير كاملاً مجزا از يكديگر مي‌باشند. هر دو اين متغيرها، متغيرهاي محلي (Local) هستند، از اينرو تنها درون بلوكي كه تعريف شده‌اند قابل دسترس مي‌باشند. به بيان ديگر اين دو متغير از وجود يكديگر اطلاعي ندارند.

 

متد getChoice() منويي را در كنسول نمايش مي‌دهد و ورودي انتخابي كاربر را دريافت مي‌نمايد. دستور return داده‌ها را از طريق متغير myChoice به متد فراخواننده آن، يعني Main()، باز مي‌گرداند. توجه داشته باشيد كه، نوع متغيري كه توسط دستور return باز گردانده مي‌شود، بايد دقيقاً همانند نوع بازگشتي متد باشد. در اين مثال نوع بازگشتي، رشته است.

 

در C# دو گونه متد وجود دارد. يكي متدهاي استاتيك (Static) و ديگري متدهاي نمونه (Instance). متدهايي كه در اعلان خود شامل كلمه كليدي static هستند، از نوع استاتيك هستند، بدين معنا كه هيچ نمونه‌اي از روي اين متد قابل ايجاد نيست و اين تنها همين نمونه موجود قابل استفاده است. از روي متدهاي استاتيك نمي‌توان شيء (Object) ايجاد كرد. در صورتيكه در اعلان متد از كلمه كليدي static استفاده نشده باشد، متد بعنوان متد نمونه در نظر گرفته مي‌شود، بدين معنا كه از روي آن مي‌توان نمونه ايجاد كرد و شيء توليد نمود. هر يك از اشياء ايجاد شده از روي اين متدها، تمامي عناصر آن متد را داراي مي‌باشند.

 

در اين مثال، چون getChoice() بصورت استاتيك اعلان نشده است، پس بايد براي استفاده از آن شيء جديدي  توليد شود. توليد شيء جديد بوسيله OneMethod om = new OneMethod() صورت مي‌پذيرد. در سمت چپ اين اعلان، مرجع اين شيء جديد، يعني om، قرار دارد كه از نوع OneMethod است. در اينجا توجه به يك نكته بسيار مهم است، om به خودي خود شيء نيست، بلكه مي‌تواند مرجعي به شي‌اي از نوع OneMethod() را در خود نگه‌دارد. در سمت راست اين اعلان، تخصيص شيء جديدي از نوع OneMethod() به متغير om صورت گرفته است. كلمه كليدي new عملگري است كه شيء جديدي را در heap ايجاد مي‌نمايد. اتفاقي كه اينجا روي داده اينست كه نمونه جديدي از OneMethod() در heap توليد شده و سپس به مرجع om تخصيص داده مي‌شود. حال كه نمونه‌اي از متد OneMethod() را به om تخصيص داده‌ايم، از طريق om مي‌توانيم با اين متد كار نماييم.

 

متدها، فيلدها و ساير اعضاي يك كلاس از طريق عملگر نقطه "." قابل دسترس هستند. هنگاميكه مي‌خواهيم متد getChoice() را فراخواني كنيم، بوسيله عملگر نقطه از طريق om به آن دسترسي پيدا مي‌نماييم : om.getChoice() . براي نگهداري مقداري كه getChoice() بر مي‌گرداند، از عملگر "=" استفاده نموده‌ايم. رشته بازگشتي از متد getChoice() درون متغير محلي myChoice متد Main() قرار مي‌گيرد. از اين قسمت، اجراي برنامه همانند قبل است.

 

پارامترهاي متد

به مثال 2-5 توجه كنيد.

using System;

 

class Address

{

public string name;

public string address;

}//Addressپايان كلاس

class MethodParams

{

public static void Main()

{

string myChoice;

MethodParams mp = new MethodParams();

do

{

// منويي نمايش داده شده و ورودي از كاربر دريافت مي‌گردد

myChoice = mp.getChoice();

// تصميمي بر اساس ورودي كاربر گرفته مي‌شود

mp.makeDecision(myChoice);

// جهت ديدن نتايج توسط كاربر، اجراي برنامه موقتا موقف مي‌گردد

Console.Write("Press Enter key to continue...");

Console.ReadLine();

Console.WriteLine();

         } while (myChoice != "Q" && myChoice != "q");

 // اجراي حلقه تا زمانيكه كاربر بخواهد ادامه پيدا مي‌نمايد

}//Mainپايان متد

// نمايش منو و دريافت ورودي از كاربر

string getChoice()

{

string myChoice;

// نمايش منو

Console.WriteLine("My Address Book\n");

Console.WriteLine("A - Add New Address");

Console.WriteLine("D - Delete Address");

Console.WriteLine("M - Modify Address");

Console.WriteLine("V - View Addresses");

Console.WriteLine("Q - Quit\n");

Console.WriteLine("Choice (A,D,M,V,or Q): ");

// دريافت ورودي كاربر

myChoice = Console.ReadLine();

return myChoice;

}//getChoice()پايان متد

// تصميم‌گيري

void makeDecision(string myChoice)

{

Address addr = new Address();

switch(myChoice)

{

case "A":

case "a":

addr.name = "Meysam";

addr.address = "C# Persian";

this.addAddress(ref addr);

   break;

case "D":

case "d":

addr.name = "Ghazvini";

this.deleteAddress(addr.name);

   break;

case "M":

case "m":

addr.name = "CSharp";

this.modifyAddress(out addr);

Console.WriteLine("Name is now {0}.", addr.name);

   break;

case "V":

case "v":

this.viewAddresses("Meysam", "Ghazvini", "C#", "Persian");

   break;

case "Q":

case "q":

Console.WriteLine("Bye.");

   break;

default:

Console.WriteLine("{0} is not a valid choice", myChoice);

   break;

}

}

// وارد كردن يك آدرس

void addAddress(ref Address addr)

{

Console.WriteLine("Name: {0}, Address: {1} added.", addr.name, addr.address);

}

// حذف يك آدرس

void deleteAddress(string name)

{

Console.WriteLine("You wish to delete {0}'s address.", name);

}

// تغيير يك آدرس

void modifyAddress(out Address addr)

{

//Console.WriteLine("Name: {0}.", addr.name); // خطا رخ مي‌دهد

addr = new Address();

addr.name = "Meysam";

addr.address = "C# Persian";

}

// نمايش آدرس‌ها

void viewAddresses(params string[] names)

{

foreach (string name in names)

{

Console.WriteLine("Name: {0}", name);

}

}

}

 

مثال 2-5، نمونه تغيير يافته مثال 1-5 است كه در آن تمامي برنامه ماژولار شده و به متدهاي مختلف تقسيم شده است. در زبان C# چهار گونه پارامتر وجود دارند : ref،  out، params و value . بمنظور آشنايي با پارامترها، در مثال 2-5 كلاسي با نام Address با دو فيلد از نوع رشته توليد كرده‌ايم.

 

درون متد Main()، متد getChoice() را فراخواني كرده‌ايم تا از كاربر ورودي دريافت كنيم و اين ورودي در متغير رشته‌اي myChoice قرار مي‌گيرد. سپس متغير myChoice را بعنوان آرگومان به متد makeDecision() ارسال نموده‌ايم. در اعلان myDecision()، همانطور كه ملاحظه مي‌نماييد، پارامتر اين متد از نوع رشته و با نام myChoice تعريف شده است. توجه نماييد كه اين متغير نيز محلي است و تنها درون متد makeDecision() قابل استفاده است. هرگاه در اعلان متد، براي پارامترهاي آن هيچ modifier آورده نشود، اين پارامتر بعنوان value در نظر گرفته مي‌شود. در مورد پارامترهاي مقداري (value parameter) ، اصل مقدار متغير يا پارامتر به پشته (Stack) كپي مي‌شود. متغيرهايي كه بصورت مقداري بعنوان پارامتر براي يك متد ارسال مي‌شوند، همگي محلي بوده و تغييرات ايجاد شده بر روي آنها به هيچ وجه تغييري بر روي متغير اصلي ايجاد نمي‌نمايد.

 

دستور switch در متد makeDecision() براي هر case يك متد را فراخواني مي‌نمايد. فراخواني اين متدها با آنچه در متد Main() ديد مقداري متفاوت است. علاوه بر مرجع mp، در اين فراخواني‌ها از كلمه كليدي this نيز استفاده شده است. كلمه كليدي this ارجاعي به شيء فعلي دارد.

 

متد addAddress() پارامتري از نوع ref دارد. وجود چنين پارامتري بدين معناست كه مرجعي از اين پارامتر به متد ارسال مي‌شود و اين مرجع همچنان به شيء اصلي درون heap نيز اشاره دارد چراكه آدرس شيء مورد نظر به متد كپي مي‌شود. در مورد پارامترهاي ref، هرگونه تغييري كه بر روي متغير محلي رخ دهد، همان تغيير بر روي متغير اصلي نيز اعمال مي‌گردد. امكان تغيير مرجع وجود ندارد و تنها شي‌اي كه مورد آدرس‌دهي واقع شده، مي‌تواند تغيير پيدا نمايد. پارامترهاي مرجعي (ref) را مي‌توان به عنوان عناصر ورودي/خروجي براي متد در نظر گرفت.

 

پارامترهاي out در مواردي استفاده مي‌شوند كه ارسال اطلاعات به متد از طريق پارامتر مد نظر نباشد، بلكه ارسال اطلاعات از متد مورد نظر باشد. استفاده از اين پارامترها از اينرو كارآمد هستند كه برنامه مجبور به كپي كردن پارامتر به متد نيست و از حجم سرباره (Overhead) برنامه مي‌كاهد. در برنامه‌هاي عادي اين مسئله چندان به چشم نمي‌آيد، اما در برنامه‌هاي تحت شبكه كه سرعت ارتباط و انتقال داده‌ها بسيار مهم است، اين پارامترها ضروري مي‌شوند.

 

متد modifyAddress() داراي پارامتري از نوع out است. پارامترهاي out فقط به متد فراخواننده آن بازگشت داده مي‌شوند. از آنجائيكه اين پارامترها از متد فراخواننده هيچ مقداري دريافت نمي‌كنند و فقط درون متدي كه به عنوان پارامتر به آن ارسال شده‌اند قابليت تغيير دارند، از اينرو درون اين متدهايي كه به آنها ارسال مي‌شوند، قبل از اينكه بتوان از آنها استفاده نمود بايد مقداري به آنها تخصيص داده شود. اولين خط در متد modifyAddress() بصورت توضيحات نوشته شده است. اين خط را از حالت توضيحات خارج كرده و سپس برنامه اجرا كنيد تا ببينيد چه اتفاقي رخ خواهد داد. هنگاميكه اين پارامتر مقدار دهي شود و مقداري را به متد فراخواننده خود بازگرداند، اين مقدار بر روي متغير متد فراخواننده كپي مي‌گردد. توجه نماييد كه پارامترهاي out مي‌بايست قبل از دستور return درون متد مقدار دهي شده باشند.

 

يكي از ويژگيهاي مفيد زبان C#، وجود پارامترهاي params است كه بوسيله آنها مي‌توان متدي را اعلان كرد كه تعداد متغيري متغير را به عنوان پارامتر دريافت نمايد. پارامترهاي params حتماً بايد يكي از انواع آرايه تك بعدي و يا آرايه دندانه‌دار (Jagged Array) باشند. در متد makeDecision() چهار متغير رشته‌اي را به متد viewAddresses() ارسال نموده‌ايم كه اين متد پارامترهاي خود را بصورت params دريافت مي‌نمايد. همانطور كه ملاحظه مي‌نماييد، تعداد متغيرهاي ارسالي به متد مي‌تواند متغير باشد اما دقت داشته باشيد كه تمامي اين متغيرها در يك آرايه تك بعدي قرار گرفته‌اند. درون متد viewAddresses() نيز با استفاده از دستور foreach تمامي عناصر موجود در اين آرايه را نمايش داده‌ايم. پارامترهاي params فقط متغيرهاي ورودي دريافت مي‌نمايند و تغييرات اعمال شده تنها بر روي متغير محلي تاثير مي‌گذارد.

 

خلاصه

در اين درس، با ساختار كلي يك متد آشنا شديد. فرا گرفتيد كه در زبان C# چهار نوع پارامتر براي متدها وجود دارند. پارامترهاي value، ref، out و params . همانطور كه گفته شد حالت پيش فرض براي پارامترها، value است مگر آنكه صريحاً مشخص گردد.

 

 

 

درس ششم – Namespaces

 

اهداف اين درس به شرح زير مي‌باشد :

ü      آشنايي با Namespace در زبان C#

ü      چگونگي استفاده از هدايتگر using (using directive)

ü      چگونگي استفاده از هدايتگر alias (alias directive)

ü      اعضاي يك Namespace چه هستند؟

 

اگر به خاطر داشته باشيد، در درس اول، در ابتداي برنامه از using System;  استفاده نموديم. با استفاده از اين كد، امكان دسترسي ما به اعضاي Namespace مورد نظر، كه در اينجه System است، فراهم مي‌شد. پس از مطالعه اين درس، مطالب بسياري درباره هدايتگر  using فرا خواهيد گرفت.

 

Namespace ها، المان‌هاي زبان C# هستند كه شما را در سازماندهي كردن برنامه، كمك مي‌كنند. پياده‌سازي Namespace ها در كد برنامه بسيار مفيد است چراكه از ايجاد مشكلات مربوط به استفاده مجدد كد، پيشگيري مي‌نمايد.

 

چگونگي ايجاد Namespace

به مثال زير توجه نماييد.

// Namespace اعلان

using System;

 

// C# Persian Namespace

namespace csharp-persian

{

// كلاس آغازين برنامه

class NamespaceCSS

{

// آغاز اجراي برنامه

public static void Main()

{

// چاپ خروجي در كنسول

Console.WriteLine("This is the new C# Persian Namespace.");

}

}

}

مثال 1-6 چگونگي ايجاد يك Namespace را نشان مي‌دهد. در اين مثال ما با قرار دادن كلمه كليدي namespace در جلوي csharp-persian يك Namespace جديد ايجاد نموديم. مثال 2-6، Namespace هاي تودرتو را نشان مي‌دهد.

// Namespace اعلان

using System;

 

// C# Persian Namespace

namespace csharp-persian

{

namespace tutorial

{

// كلاس آغازين برنامه

class NamespaceCSS

{

// آغاز اجراي برنامه

public static void Main()

{

 // چاپ خروجي در كنسول

Console.WriteLine("This is the new C# Persian Namespace.");

}

}

}

}

 

Namespace ها اين امكان را فراهم مي‌آورند تا سيستمي جهت سازماندهي كدهاي خود ايجاد نماييد. يك روش مناسب جهت سازماندهي Namespace هاي برنامه، استفاده از يك سيستم سلسله مراتبي است. بدين ترتيب كه Namespace هاي عمومي را در بالاي اين ساختار قرار داده و هر چه در اين ساختار پاين‌تر مي‌آييم، Namespace هاي تخصصي‌تر قرار مي‌گيرند. اين سيستم سلسله مراتبي بوسيله Namespace هاي تودرتو قابل پياده‌سازي هستند. اين پياده‌سازي در مثال 2-6 نشان داده شده است. با قرار دادند كدهاي خود در Namespace هاي فرعي مي‌توانيد كدهاي خود را سازماندهي نماييد.

// Namespace اعلان

using System;

 

// C# Persian Tutorial Namespace

namespace csharp-persian.tutorial

{

 // كلاس آغازين برنامه

class NamespaceCSS

{

 //آغاز اجراي برنامه

public static void Main()

{

 // چاپ خروجي در كنسول

Console.WriteLine("This is the new C# Persian Namespace.");

}

}

}

مثال 3-6 روش ديگر ايجاد Namespace هاي تودرتو را نشان مي‌دهد. همانطور كه در اين مثال مشاهده مي‌نماييد، Namespace تودرتو با قرار دادن عملگر نقطه "." در بين csharp-persian و tutorial ايجاد شده است. اين مثال از نظر كارآيي دقيقاً همانند مثال 2-6 است و از نظر پياده‌سازي آسان‌تر از آن مي‌باشد.

 

فراخواني اعضاي يك Namespace

// Namespace اعلان

using System;

 

namespace csharp-persian

{

// namespace تودرتو

namespace tutorial

{

class myExample1

{

public static void myPrint1()

{

Console.WriteLine("First Example of calling another namespace member.");

}

}

}

 // كلاس آغازين برنامه

class NamespaceCalling

{

 // آغاز اجراي برنامه

public static void Main()

{

 // چاپ خروجي در كنسول

tutorial.myExample1.myPrint1();

tutorial.myExample2.myPrint2();

}

}

}

 

//تودرتو بالا Namespaceمشابه  Namespace  

namespace csharp-persian.tutorial

{

class myExample2

{

public static void myPrint2()

{

Console.WriteLine("Second Example of calling another namespace member.");

}

}

}

 

مثال 4-6 چگونگي فراخواني اعضاي Namespace نشان مي‌دهد. در ابتداي مثال 4-6، يك Namespace تودرتو اعلان شده است، tutorial درون csharp-persian، كه داراي كلاس myExample1 و متد myPrint1 مي‌باشد. متد Main() اين متد را با نام tutorial.myExample1.myPrint1 فراخواني مي‌نمايد. چون متد Main() و tutorial درون يك Namespace قرار دارند، ديگر نيازي به استفاده از نام csharp-persian غير ضروري است.

 

در انتهاي مثال 4-6، يك Namespace ديگر بصورت csharp-persian.tutorial آورده شده است. كلاسهاي myExamlpe1 و myExample2 هر دو متعلق به يك Namespace مي‌باشند، هرچند مي‌تواند آنها را مجزا از يكديگر نوشت در حاليكه متعلق به يك Namespace باشند. درون متد Main()، متد myPrint2 بصورت tutorial.myExample2.myPrint2 فراخواني شده است. هرچند كلاس myExample2 خارج از محدوده‌ايست كه متد myPrint2 فراخواني شده است، نيازي به آمردن نام csharp-persian براي اين فراخواني وجود ندارد، زيرا هر دو كلاس متعلق به يك Namespace، يعني csharp-persian هستند.

 

توجه نماييد كه براي هر يك از كلاسهاي myExample1 و myExample2 نامهاي متفاوتي انتخاب شده است، زيرا هر عضو متعلق به يك Namespace بايد داراي نام يكتايي باشد. براي متدهاي myPrint1 و myPrint2 ، بعلت سادگي در امر يادگيري اين مطلب، نامهاي متفاوتي در نظر گرفته شده است. توجه نماييد كه اين دو متد بعلت اينكه در كلاسهاي متفاوتي قرار دارند، مي‌توان نامهاي يكساني برايشان انتخاب نمود، و در اينصورت هيچگونه تداخلي بين ايندو ايجاد نخواهد شد.

 

استفاده از هدايتگر using

// Namespace اعلان

using System;

using csharp_station.tutorial;

 

// كلاس آغازين برنامه

class UsingDirective

{

 // آغاز اجراي برنامه

public static void Main()

{

 // Namespace فراخواني عضوي از

myExample.myPrint();

}

}

// C# PersianTutorial Namespace

namespace csharp-persian.tutorial

{

class myExample

{

public static void myPrint()

{

Console.WriteLine("Example of using a using directive.");

}

}

}

 

در صورتيكه مي خواهيد متدهايي را بدون استفاده از نام كامل آنها،‌به همراه نام Namespace، استفاده نماييد، مي‌توانيد از هدايتگر using استفاده نماييد. در مثال 5-6، دوبار از هدايتگر using استفاده شده است. اولين استفاده از اين هدايتگر، using System،‌ دقيقاً مشابه به همان چيزي است كع تا كنون در اين درسها مشاهده نموده‌ايد. با استفاده از اين هدايتگر مي‌توانيد از اعضاي موجود در System، بدون اينكه نياز به تايپ كلمه System در هربار داشته باشيد، استفاده نماييد. در myPrint()، كلاس Console عضوي از System است كه داراي متد WriteLine() مي‌باشد. اگر در ابتداي برنامه از هدايتگر using استفاده نكنيم، بايد براي هر دفعه استفاده از متد WriteLine()، نام كامل آن يعني System.Console.WriteLine() را تايپ نماييم.

 

به طور مشابه، استفاده از using csharp-persian.tutorial امكان استفاده از اعضاي اين Namespace را، بدون نياز به تايپ نام كامل آنها فراهم مي‌نمايد. چون در ابتداي برنامه از هدايتگر using استفاده نموده‌ايم، در متن برنامه متد myPrint() را بصورت myExample.myPrint() استفاده نموده‌ايم، درصورتيكه از هدايتگر using استفاده نمي‌گرديم براي استفاده از اين متد بايد آنرا بصورت csharp-persian.tutorial.myExample.myPrint() مي‌آورديم.

 

استفاده از هدايتگر Alias

// Namespace اعلان

using System;

using csTut = csharp-persian.tutorial.myExample; // alias

 

// كلاس آغازين برنامه

class AliasDirective

{

 // آغاز اجراي برنامه

public static void Main()

{

 // Namespace فراخواني عضوي از

csTut.myPrint();

myPrint();

}

 // متدي كه ممكن است توليد ابهام نمايد.

static void myPrint()

{

Console.WriteLine("Not a member of csharp-persian.tutorial.myExample.");

}

}

// C# Persian Tutorial Namespace

namespace csharp-persian.tutorial

{

class myExample

{

public static void myPrint()

{

Console.WriteLine("This is a member of csharp-persian.tutorial.myExample.");

}

}

}

در برخي موارد ممكن است با Namespace خاصي روبرو شويد كه داراي نامي طولاني است و تمايل داشته باشيد تا نام آنرا كوتاهتر نماييد. اين كار با استفاده از ايجاد استعاره (Alias) امكان‌پذير است. همانطور كه در مثال 6-6 ملاحظه مي‌نماييد، با استفاده از

 csTut = csharp-persian.tutorial.myExample يك استعاره توليد كرده‌ايم و در متن برنامه به جاي استفاده از نام طولاني csharp-persian.tutorial.myExample از نام مستعار آن يعني csTut استفاده نموده‌ايم. حال از اين نام مستعار در هر جاي برنامه مي‌توان استفاده كرد. ما در اين برنامه در متد Main() استفاده نموده‌ايم.

 

همچنين در متد Main()، فراخواني از متد myPrint() مربوط به كلاس AliasDirective صورت گرفته است. نام اين متد همانند myPrint() موجود در myExample است. علت اينكه مي‌توان هر دو اين متدها را همزمان فراخواني كرد، استفاده از هدايتگر alias براي متد myPrint() مربوط به كلاس myExample است. (csTut.myPrint()) استفاده از اين روش باعث مي‌شود تا كامپايلر دريابد كه كدام متد را بايد اجرا نمايد. در صورتيكه به اشتباه از هدايتگر alias (csTut.myPrint()) استفاده نكنيم، كامپايلر به اشتباه متد myPrint() مربوط به كلاس AliasDirective را دوبار اجرا خواهد كرد.

 

تا اينجا،‌ما تنها كلاسها را در Namespace ها نشان داديم. Namespace ها انواع ديگري را نيز مي‌توانند در خود داشته باشند كه در زير مشاهده مي‌نماييد :

Classes

Structures

Interfaces

Enumerations

Delegates

خلاصه

در اين درس با Namespace آشنا شديد و فراگرفتيد كه چگونه Namespace خود را اعلان نماييد. اگر نخواهيد در هربار استفاده از متدها يا اعضاي يك Namespace، نام كامل آنها را استفاده كنيد، بايد از هدايتگر using استفاده نماييد. در صورتيكه بخواهيد بجاي استفاده از نام طولاني يك Namespace، از نامي ك.وتاهتر استفاده كنيد، بايد از هدايتگر استعاره‌اي (Alias Directive) استفاده نماييد.

 

 

درس هفتم – آشنايي با كلاسها در C#

 

در اين درس با كلاسها در زبان C# آشنا خواهيد شد. اهداف اين درس به شرح زير مي‌باشند :

ü      پياده‌سازي سازنده‌ها (Constructors)

ü      درك تفاوت بين اعضاي نمونه (Instance) و استاتيك (Static)

ü      آشنايي با تخريب كننده‌ها (Destructors)

ü      آشنايي با اعضاي كلاسها

 

در تمامي مطالبي كه در اين سايت مشاهده كرده‌ايد، برنامه‌ها داراي كلاس‌هايي بوده‌اند. در حال حاضر بايد درك نسبي از كلاسها و كار آنها و چگونگي ايجاد آنها داشته باشيد. در اين درس مروري بر آموخته‌هاي قبلي از كلاسها خواهيم كرد و نيز با اعضاي كلاسها آشنا مي‌شويم.

 

يك كلاس با استفاده از كلمه كليدي class كه بدنبال آن نام كلاس آمده باشد، اعلان مي‌گردد و اعضاي اين كلاس درون {} اعلان مي‌گردند. هر كلاس داراي سازنده‌اي مي‌باشد كه در هربار ايجاد نمونه‌اي جديد از آن كلاس، بصورت خودكار فراخواني مي‌گردد. هدف از سازنده، تخصيص‌دهي اعضاي كلاس در زمان ايجاد نمونه‌اي جديد از كلاس است. سازنده‌ها داراي مقادير بازگشتي نبوده و همواره نامي مشابه نام كلاس دارند. مثال 1-7 نمونه‌اي از يك كلاس را نشان مي‌دهد.

// Namespace اعلان

using System;

 

class OutputClass

{

string myString;

// سازنده

public OutputClass(string inputString)

{

myString = inputString;

}

 // متد نمونه

public void printString()

{

Console.WriteLine("{0}", myString);

}

// تخريب كننده

~OutputClass()

{

// روتيني جهت آزادسازي برخي از منابع سيستم

}

}

// كلاس آغازين برنامه

class ExampleClass

{

// آغاز اجراي برنامه

public static void Main()

{

// OutputClass نمونه‌اي از

OutputClass outCl = new OutputClass("This is printed by the output class.");

 // Output فراخواني متد كلاس

outCl.printString();

}

}

در مثال 1-7 دو كلاس ديده مي‌شوند. كلاس بالايي، كلاس OutPutClass، داراي سازنده، متد نمونه و يك تخريب كننده است. همچنين اين كلاس داراي فيلدي با نام myString است. توجه نماييد كه چگونه سازنده اين كلاس اعضاي آنرا تخصيص‌دهي(مقداردهي) مي‌نمايد. در اين مثال، سازنده كلاس رشته‌ ورودي (inputString) را بعنوان آرگومان خود دريافت مي‌نمايد. سپس اين مقدار داخل فيلد كلاس يعني myString كپي مي‌گردد.

 

همانطور كه در ExampleClass مشاهده مي‌نماييد، استفاده از سازنده الزامي نمي‌باشد. در اين مورد سازنده پيش فرض ايجاد مي‌گردد. سازنده پيش فرض، سازنده‌اي بدون هيچ نوع آرگوماني است. البته شايان ذكر است كه سازنده‌هاييي بدون آرگومان هميشه مورد استفاده نبوده و مفيد نيستند. جهت كارآمد كردن بيشتر سازنده‌هاي بدون آرگومان بهتر است آنها را با تخصيص‌دهنده (Initializers) پياده‌سازي نماييد. به مثال زير در اين زمينه توجه نماييد :

public OutputClass() : this("Default Constructor String") { }

فرض كنيد اين عبارت در كلاس OutPutClass در مثال 1-7 قرار داشت. اين سازنده پيش فرض به يك تخصيص‌دهنده همراه شده است. ":" ابتداي تخصيص‌دهنده را مشخص ‌مي‌نما‌يد، و به دنبال آن كلمه كليدي this آمده است. كلمه كليدي this به شيء كنوني اشاره مي‌نمايد. استفاده از اين كلمه، فراخواني به سازنده شيء كنوني كه در آن تعريف شده است، ايجاد مي‌كند. بعد از كلمه كليدي this ليست پارامترها قرار مي‌گيرد كه در اينجا يك رشته است. عملي كه تخصيص‌دهنده فوق انجام مي‌دهد، باعث مي‌شود تا سازنده OutPutClass رشته‌اي را بعنوان آرگومان دريافت نمايد. استفاده از تخصيص‌دهنده‌ها تضمين مي‌نمايند كه فيلدهاي كلاس شما در هنگام ايجاد نمونه‌اي جديد مقدار‌دهي مي‌شوند.

 

مثال فوق نشان داد كه چگونه يك كلاس مي‌تواند سازنده‌هاي متفاوتي داشته باشد. سازنده‌اي كه فراخواني مي‌شود، به تعداد و نوع آرگومانهايش وابسته است.

 

در زبان C#، اعضاي كلاسها دو نوع مي‌باشند : اعضاي نمونه و استاتيك.  اعضاي نمونه كلاس متعلق به رخداد خاصي از كلاس هستند. هربار كه شي‌اي از كلاسي خاص ايجاد مي‌كنيد، در حقيقت نمونه‌ جديدي از آن كلاس ايجاد كرده‌ايد. متد Main() در كلاس ExampleClass نمونه جديدي از OutPutClass را تحت نام outCl ايجاد مي‌نمايد. مي‌توان نمونه‌هاي متفاوتي از كلاس OutPutClass را با نامهاي مختلف ايجاد نمود. هر يك از اين نمونه‌هاي مجزا بوده و به تنهايي عمل مي‌كنند. به عنوان مثال اگر دو نمونه از كلاس OutPutClass همانند زير ايجاد نماييد :

OutputClass oc1 = new OutputClass("OutputClass1");

OutputClass oc2 = new OutputClass("OutputClass2");

با اين اعلان، شما دو نمونه از كلاس OutPutClass را ايجاد كرده‌ايد كه يك از آنها داراي فيلد myString و متد printString() هستند و اين فيلدها و متدها كاملاً از يكديگر مجزا مي‌باشند. به بيان ديگر درصورتيكه عضوي از كلاس استاتيك باشد از طريق ساختار نوشتاري . قابل دسترس خواهد بود. در اين مثال نمونه‌ها oc1 و oc2 هستند. فرض كنيد كلاس OutPutClass داراي متد استاتيك زير باشد :

public static void staticPrinter()

{

  Console.WriteLine("There is only one of me.");

}

اين متد را از درون متد Main() به صورت زير مي‌توانيد فراخواني نماييد :

OutputClass.staticPrinter();

اعضاي استاتيك يك كلاس تنها از طريق نام آن كلاس قابل دسترس مي‌باشند و نه از طريق نام نمونه ايجاد شده از روي كلاس. بدين ترتيب براي فراخواني اعضاي استاتيك يك كلاس نيازي به ايجاد نمونه از روي آن كلاس نمي‌باشد. همچنين تنها يك كپي از عضو استاتيك كلاس، در طول برنامه موجود مي‌باشد. يك مورد استفاده مناسب از اعضاي استاتيك در مواردي است كه تنها يك عمل بايد انجام گيرد و در انجام اين عمل هيچ حالت مياني وجود نداشته باشد، مانند محاسبات رياضي. در حقيقت، .Net Framework BCL خود داراي كلاس Math مي‌باشد كه از اعضاي استاتيك بهره مي‌برد.

 

نوع ديگر سازنده‌ها، سازنده‌هاي استاتيك هستند. از سازنده‌هاي استاتيك جهت مقدار‌دهي فيلدهاي استاتيك يك كلاس استفاده مي‌شود. براي اعلان يك سازنده استاتيك تنها كافيست كه از كلمه كليدي static در جلوي نام سازنده استفاده نماييد. سازنده استاتيك قبل از ايجاد نمونه جديدي از كلاس، قبل از فراخواني عضو استاتيك و قبل از فراخواني سازنده استاتيك كلاس مشتق شده، فراخواني مي‌گردد. اين سازنده‌ها تنها يكبار فراخواني مي‌شوند.

 

OutPutClass همچنين داراي يك تخريب‌كننده (Destructor) است. تخريب‌كننده‌ها شبيه به سازنده‌ها هستند، با اين تفاوت كه در جلوي خود علامت "~" را دارا مي‌باشند. هيچ پارامتري دريافت نكرده و هيچ مقداري باز نمي‌گردانند. از تخريب‌كننده‌ها مي‌توان در هر نقطه از برنامه كه نياز به آزادسازي منابع سيستم كه در اختيار كلاس يا برنامه است، استفاده نمود. تخريب‌كننده‌ها معمولاً زماني فراخواني مي‌شوند كه Garbage Collector زبان C# تصميم به حذف شيء مورد استفاده برنامه از حافظه و آزادسازي منابع سيستم، گرفته باشد. (Garbage Collector يا GC، يكي از امكانات .Net Framework مخصوص زبان C# است كه سيستم بصورت اتوماتيك اقدام به آزادسازي حافظه و باز گرداندن منابع بلا استفاده به سيستم مي‌نمايد. فراخواني GC بصورت خودكار رخ مي‌دهد مگر برنامه‌نويس بصورت صريح از طريق تخريب‌كننده‌ها آنرا فراخواني نمايد. در مباحث پيشرفته‌تري كه در آينده مطرح مي‌كنيم خواهيد ديد كه در چه مواقعي نياز به فراخواني تخريب‌كننده‌ها بصورت شخصي داريد.)

 

تا كنون، تنها اعضاي كلاس كه با آنها سر و كار داشته‌ايد، متدها، فيلدها، سازنده‌ها و تخريب‌كننده‌ها بوده‌اند در زير ليست كاملي از انواعي را كه مي‌توانيد در كلاس از آنها استفاده نماييد آورده شده است :

• Constructors

• Destructors

• Fields

• Methods

• Properties

• Indexers

• Delegates

• Events

• Nested Classes

مواردي كه در اين درس با آنها آشنا نشديد، حتماً در درس‌هاي آينده مورد بررسي قرار خواهند گرفت.

 

خلاصه

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