آموزش برنامه نویسی

آموزش سی شارپ

آموزش سی شارپ

پربیننده ترین مطالب
پیوندهای روزانه

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

  1. آشنایی با کلمات کلیدی ref و out
  2. استفاده از آرایه به عنوان ورودی و خروجی متد
  3. آشنایی با کلمه کلیدی params
  4. قابلیت method overloading و کاربرد آن
  5. نوشتن توابع بازگشتی

کلمات کلیدی out و ref


در قسمت قبل در مورد پارامترها در متدها صحبت کردیم. پارامترها مقادیری هستند که به یک متد ارسال می شوند. دو کلمه کلیدی ref و out در زبان سی شارپ وجود دارند که نوع رفتار با یک پارامتر را تغییر می دهند. ابتدا با یک مثال ساده شروع می کنیم. کد زیر را در نظر بگیرید:

private static void Main(string[] args)
{
    var number = 8;
    Console.WriteLine(number);
    Do(number);
    Console.WriteLine(number);
}

public static void Do(int num)
{
    num = 12;
}

متغیری با نام number تعریف کردیم و مقدار آن را برابر 8 قرار دادیم. سپس این متغیر را در خروجی چاپ کرده و هنگام فراخوانی متد Do متغیر number را به آن ارسال کردیم. در داخل متد Do مقدار پارامتر را به 12 تغییر دادیم و مجدد مقدار number را در خروجی چاپ کردیم. اگر خروجی برنامه را مشاهده کنید، دو بار عدد 8 در خروجی چاپ خواهد شد. دلیل آن، ارسال مقدار به پارامتر متد می باشد. زمانی که ما برای مقدار یک پارامتر از یک متغیر تعریف شده استفاده می کنیم، مانند مثال بالا، مقدار متغیر داخل پارامتر متد کپی می شود و در صورت تغییر دادن مقدار پارامتر، متغیر ما تغییری نخواهد کرد. اما می توان این رفتار را تغییر داد. کلمه کلیدی ref هنگام تعریف پارامتر، می گوید به جای کپی کردن مقدار متغیر داخل پارامتر، از آدرس متغیر تعریف شده برای پارامتر استفاده کن. یعنی، آدرس متغیر تعریف شده به پارامتر تخصیص داده شده و پارامتر و متغیر، هر دو به یک خانه حافظه اشاره می کنند. در این شرایط، با تغییر مقدار پارامتر، مقدار متغیر نیز تغییر خواهد کرد. هنگام تعریف پارامتر کافیست قبل از نوع پارامتر کلمه کلیدی ref را بنویسیم. کد بالا ره به صورت زیر تغییر می دهیم:

private static void Main(string[] args)
{
    var number = 8;
    Console.WriteLine(number);
    Do(ref number);
    Console.WriteLine(number);
}

public static void Do(ref int num)
{
    num = 12;
}

در صورتی که کد بالا را مجدد اجرا کنیم، ابتدا عدد 8 و پس از فراخوانی متد، عدد 12 در خروجی چاپ می شود، زیرا پارامتر num در متد Do را از نوع ref تعریف کردیم. دقت کنید که هنگام فراخوانی متد، باید قبل از نام متغیر کلمه کلیدی ref نوشته شود، در غیر این صورت برنامه کامپایل نشده و پیغام خطا دریافت خواهید کرد. نکته بعدی که باید به آن توجه کنید، زمانی که از کلمه کلیدی ref استفاده می کنید، نمی توانید مقداری را به صورت مستقیم به عنوان ورودی پارامتر زمان فراخوانی متد استفاده کنید، یعنی برای ورودی تنها مجاز به استفاده از نام یک متغیر که تعریف کرده اید خواهید بود، کد زیر صحیح نبوده و کامپایل نمی شود:

private static void Main(string[] args)
{
    Do(ref 18);
}

کلمه کلیدی دیگری که در پارامترها کاربرد دارد، کلمه کلیدی out می باشد. نحوه کارکرد out دقیقاً مانند ref می باشد، با این تفاوت که زمانی که یک پارامتر از نوع out تعریف می شود، حتماً باید داخل بدنه متد آن را مقدار دهی کرد، اما ref به این صورت نیست. کد زیر را در نظر بگیرید:

private static void Main(string[] args)
{
    int sum;
    int substact;
    Calc(12, 3, out sum, out substact);
    Console.WriteLine(sum);
    Console.WriteLine(substact);
}

public static void Calc(int num1, int num2, out int sum, out int substract)
{
    sum = num1 + num2;
    substract = num1 - num2;
}

در متد Calc، دو پارامتر sum و substract از نوع out تعریف شده اند، یعنی حتماً باید این دو پارامتر داخل بدنه متد مقدار دهی شوند. در صورتی که یکی از پارامترها مقدار دهی نشود، با پیغام خطا روبرو خواهید شد. یکی از مهمترین کاربردهای out زمانی است که می خواهید متدی بیش از یک خروجی داشته باشد.


آرایه به عنوان ورودی و خروجی متد


موقعیتی را در نظر بگیرید که می خواهید میانگین اعداد ورودی یک متد را حساب کرده و به عنوان خروجی برگردانید. یک راه حل این کار استفاده از آرایه به عنوان ورودی متد می باشد. به مثال زیر دقت کنید:

private static void Main(string[] args)
{
    var average = Average(new[] {2, 6, 8, 1, 2});
    Console.WriteLine(average);
}

public static int Average(int[] numbers)
{
    var sum = 0;
    foreach (var number in numbers)
        sum += number;
    return sum/numbers.Length;
}

در کد بالا، پارامتر ورودی Average از نوع آرایه تعریف شده و میانگین اعداد آرایه حساب شده و به عنوان خروجی باز گردانده خواهند شد. حال فرض کنید که می خواهیم تعداد 10 عدد از اعداد اول را حساب کرده و به عنوان خروجی برگردانیم. در این موقعیت می توانیم خروجی متد را از نوع آرایه در نظر بگیریم:

private static void Main(string[] args)
{
    foreach (var primeNumber in PrimeNumbers())
    {
        Console.WriteLine(primeNumber);
    }
}

public static int[] PrimeNumbers()
{
    var numbers = new int[10];
    var number = 1;
    var index = 0;
    while (index < 10)
    {
        if (IsPrime(number))
            numbers[index++] = number;
        number++;
    }
    return numbers;
}

public static bool IsPrime(int number)
{
    if (number <= 3)
        return true;
    for (int counter = 2; counter < number; counter++)
    {
        if (number%counter == 0)
            return false;
    }
    return true;
}

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


کلمه کلیدی params


در قسمت بررسی آرایه ها به عنوان ورودی و خروجی، برنامه ای نوشتیم که اعدادی را به عنوان ورودی متد دریافت کرده و سپس میانگین آن را حساب می کرد. برای اینکار از آرایه به عنوان ورودی استفاده کردیم. اما راه حل دیگر آن استفاده از کلمه کلیدی params می باشد. بوسیله این کلمه کلیدی می توانید 1 تا n مقدار را برای آن پارامتر مشخص کنیم بدون اینکه در هنگام فراخوانی متد آرایه ای تعریف کنیم. در حقیقت مقادیر به صورت پشت سر هم و با علامت , از هم جدا می شوند. کد میانگین را تغییر داده و از کلمه کلیدی params استفاده می کنیم:

private static void Main(string[] args)
{
    var average = Average(2, 8, 9, 3, 1 , 3);
    Console.WriteLine(average);
}

public static int Average(params int[] numbers)
{
    var sum = 0;
    foreach (var number in numbers)
        sum += number;
    return sum / numbers.Length;
}


به این موضوع دقت داشته باشید که تنها آخرین پارامتر متد می تواند از نوع params باشد و تنها یک پارامتر، یعنی شما نمی توانید دو پارامتر برای متد را از نوع params تعریف کنید.


آشنایی با مفهوم Method Overloading


زمانی که شما متدی را تعریف می کنید، می توانید چندین متد همنام دیگر با آن متد داشته باشید، به شرط آنکه ورودی ها و خروجی های آن ها با هم متفاوت باشند. در حقیقت، Signature آنها با هم تفاوت داشته باشند. Signature یک متد شامل نوع بازگشتی، نام و نوع پارامترهای آن می باشد. در مثال زیر، یک متد و Signature آن نوشته شده اند:

public static int Multiply(int number1, int number2) // Signature => int Multiply(int, int)
{

}

برای آشنایی بیشتر فرض کنید، متدی نوشته ایم که نام و نام خانوداگی را به عنوان ورودی دریافت کرده و یک پیغام مناسب در خروجی چاپ می کند:

private static void Main(string[] args)
{
    DisplayMessage("mobin", "khosravi");
}

public static void DisplayMessage(string firstName, string lastName)
{
    Console.WriteLine("Welcome dear " + firstName + " " + lastName + ".");
}

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

private static void Main(string[] args)
{
    DisplayMessage("mobin", "khosravi", 29);
}

public static void DisplayMessage(string firstName, string lastName)
{
    Console.WriteLine("Welcome dear " + firstName + " " + lastName + ".");
}

public static void DisplayMessage(string firstName, string lastName, byte age)
{
    DisplayMessage(firstName, lastName);
    Console.WriteLine("You are " + age + " years old!");
}

در این حالت، ما می توانیم هر دو نسخه متد DisplayMessage را صدا بزنیم. یعنی هم بدون پارامتر Age و هم با پارامتر Age. زمانی که متدی دارای Overload باشد، Intellisense در Visual Studio زمان فراخوانی متد، لیستی از تمام Overload های آن متد را به ما نمایش می دهد:


p1


متد WriteLine که در کدها از آن استفاده می کنیم نیز دارای Overload های بسیاری است:

p2



متدهای بازگشتی یا Recursive Methods


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

n! = n * (n - 1) * (n - 2) * ... * 1

این متد را به صورت بازگشتی می نویسیم:

private static void Main(string[] args)
{
    Console.WriteLine(Fact(4));
}

public static int Fact(int num)
{
    if (num == 1)
        return num;
    return num*Fact(num - 1);
}

همانطور که مشاهده می کنید، داخل بدنه متد Fact، مجدد آن را فراخوانی کردیم. دقت کنید که زمان فراخوانی مجدد متد، از پارامتر num یک عدد کم کردیم و به عنوان پارامتر استفاده کردیم. همچنین داخل بدنه متد، باید شرطی وجود داشته باشد که از تکرار بی نهایت متد جلوگیری کند، در غیر اینصورت با خطای Stack Overflow مواجه خواهید شد. هر بار فراخوانی یک واحد از num کم می شود و زمانی که پارامتر num به مقدار 1 برسد، فراخوانی مجدد انجام نشده و زنجیر وار، فراخوانی متدها به پایان خواهد رسید.

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

منبع:programming.itpro.ir
  • متین تیماسی ، مبین خسروی و عمران جودکی

نظرات  (۰)

هیچ نظری هنوز ثبت نشده است
ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی