زنگ سی شارپ – قسمت بیست و پنجم

نگاهی دقیق به چگونگی ارسال argument از طریق reference و آشنایی با کلمات کلیدی ref ،out و params


۳۴ دیدگاه سی شارپ جمعه, ۲۰ام بهمن , ۱۳۹۱ 19161 بازدید

فرستادن Reference به متدها

تا این قسمت از زنگ سی‌شارپ، پارامترهایی که به متد داده می‌شدند همه‌گی  value type بودند (مانند int یا double و…) اما علاوه بر value type شما می‌توانید از reference type نیز به‌عنوان پارامتر استفاده کنید. این‌کار به یک شیء اجازه می‌دهد تا بتواند به یک متد فرستاده شود.

زنگ سی‌شارپ - قسمت بیستم و چهارم

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

using System;
class MyClass
{
    string Name;
    string Surname;
    int Age;

    // Constructor
    public MyClass(string name, string surname, int age)
    {
        Name = name;
        Surname = surname;
        Age = age;
    }

    // Return true if ob contains the same values as the invoking object.
    public bool SameAs(MyClass ob)
    {
        if (Name == ob.Name && Surname == ob.Surname && Age == ob.Age)
            return true;
        else return false;
    }

    // Make a copy of ob
    public void Copy(MyClass ob)
    {
        Name = ob.Name;
        Surname = ob.Surname;
        Age = ob.Age;
    }

    public void Show()
    {
        Console.WriteLine("  Name: {0}, Surname: {1}, Age: {2}",
            Name, Surname, Age);
    }
}
class PassOb
{
    static void Main()
    {
        MyClass ob1 = new MyClass("Damon", "Salvatore", 22);
        MyClass ob2 = new MyClass("Stefan", "Salvatore", 21);

        Console.WriteLine("ob1: ");
        ob1.Show();
        Console.WriteLine("ob2: ");
        ob2.Show();

        Console.WriteLine();

        if (ob1.SameAs(ob2))
            Console.WriteLine("ob1 and ob2 have the same values.");
        else
            Console.WriteLine("ob1 and ob2 have different values.");

        // Now, make ob1 a copy of ob2
        ob1.Copy(ob2);
        Console.WriteLine();
        Console.WriteLine("ob1 after copy: ");
        ob1.Show();

        Console.WriteLine();
        if (ob1.SameAs(ob2))
            Console.WriteLine("ob1 and ob2 have the same values.");
        else
            Console.WriteLine("ob1 and ob2 have different values.");
    }
}

متد ()SameAs و متد ()Copy هرکدام یک Reference را به‌عنوان argument دریافت می‌کنند (همان‌طور که می‌دانید Reference آدرس یک شیء در حافظه است). متد ()SameAs مقادیر Name، Surname و Age را از متدی که فراخوانی شده با مقادیر Name، Surname و Age شیء ob که به متد داده شده است، مقایسه می‌کند و در صورت یکسان بودن این مقادیر،true برمی‌گرداند. متد ()Copy نیز مقادیر شیء ob را به مقادیر شیء فراخوانی‌شده اختصاص می‌دهد. همان‌طور که می‌بینید به همان روشی که value type ها به متدها داده می‌شوند، reference type ها نیز داده شده‌اند.

از دو طریق Argument ها به parameter ها فرستاده می‌شوند:

  • Call-by-value
  • Call-by-reference

در روش اول (call-by-value) از مقدار argument یک کپی گرفته شده و به پارامتر داده می‌شود. از این‌رو، هر بلایی که سر پارامتر آورید هیچ تغییری روی argument صورت نمی‌گیرد.

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

using System;
class MyClass
{
    static void Main()
    {
        int a = 5;
        Change(a);
        Console.WriteLine(a);
    }
    static void Change(int x)
    {
        x++;
    }
}

مقدار a برابر با ۵ است.argument متد ()Change مقدارa است. از این مقدار یک کپی گرفته شده و به پارامتر این متد (x) فرستاده می‌شود. هنگامی‌که درون این متد مقدار x افزایش می‌یابد. تغییر x هیچ تاثیری روی مقدار a نمی‌گذارد. به شکل زیر توجه کنید:

همان‌طور که می‌بینید با تغییر پارامتر، مقدار a هیچ تغییری نمی‌کند زیرا کپی مقدار a در x قرار دارد و این‌دو کاملاً مستقل از هم هستند.

در روش دوم (call-by-reference) یک reference به‌عنوان argument به متد داده شده و کپی این reference به پارامتر فرستاده می‌شود. درون متد، پارامتر به همان شیءای رجوع می‌کند که argument رجوع می‌کند. این یعنی اگر هر تغییری روی پارامتر انجام دهید، این تغییر روی argument نیز تاثیر می‌گذارد زیرا هردو به یک شیء وصل هستند و تغییر هرکدام، شیء را تحت تاثیر قرار می‌دهد.

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

// Objects are passed by reference.
using System;
class Test
{
    public int a, b;
    public Test(int i, int j)
    {
        a = i;
        b = j;
    }
    /* Pass an object. Now, ob.a and ob.b in object
    used in the call will be changed. */
    public void Change(Test ob)
    {
        ob.a = ob.a + ob.b;
        ob.b = -ob.b;
    }
}
class CallByRef
{
    static void Main()
    {
        Test ob = new Test(15, 20);
        Console.WriteLine("ob.a and ob.b before call: " +
        ob.a + " " + ob.b);
        ob.Change(ob);
        Console.WriteLine("ob.a and ob.b after call: " +
        ob.a + " " + ob.b);
    }
}

همان‌طور که می‌بینید تغییر در پارامتر متد ()Change باعث تغییر مقادیر شیء می‌شود.

همان‌طور که می‌بینید تغییرات در متد ()Change موجب تغییر شیءای می‌شود که argument نیز به آن رجوع می‌کرد.

استفاده از پارامترهای ref و out

همان‌طور که گفته شد، value type ها از طریق مقدارشان به یک متد فرستاده می‌شوند و تغییر در پارامترهایی که argument را دریافت می‌کنند، در argument تغییری ایجاد نمی‌کند. سی‌شارپ به شما اجازه می‌دهد که این رفتار را از طریق کلمات کلیدی ref و out تغییر دهید. در سی‌شارپ این امکان وجود دارد که value type را توسط reference ارسال کنید. این‌کار به متد این امکان را می‌دهد تا بتواند argument را تغییر دهد.

پیش از اینکه به چگونگی مکانیسم ref و out بپردازیم نیاز است بدانید که چرا باید value type را توسط reference ارسال کنیم. به‌صورت کلی، دو دلیل برای این‌کار وجود دارد: اجازه دادن به متد تا بتواند محتوای argument اش را تغییر دهد. اجازه دادن به متد برای اینکه بتواند بیشتر از یک مقدار را return کند.

ref Parameter Modifier

اغلب شما می‌خواهید یک متد بتواند روی argument هایی که به آن داده می‌شود تغییرات اعمال کند. ساده‌ترین مثال می‌تواند متد ()Swap باشد که دو متغیر را می‌گیرد و مقادیر آن‌ها را جابه‌جا می‌کند. در حالت عادی این امکان وجود ندارد که متدی بنویسید تا عملیات swap را انجام دهد اما کلمه کلیدی ref این مشکل را حل می‌کند.

ref modifier موجب می‌شود سی‌شارپ به‌جای call-by-value یک call-by-reference ایجاد کند.ref modifier زمانی که متد ساخته و صدا زده می‌شود، مشخص می‌شود. بهتر است با یک مثال موضوع را روشن‌تر کنیم. برنامه زیر یک متد به اسم ()Sqr دارد که این متد مقدار داده شده به آن را به توان ۲ می‌رساند:

// Use ref to pass a value type by reference.
using System;
class RefTest
{
    // This method changes its argument. Notice the use of ref.
    public void Sqr(ref int i)
    {
        i = i * i;
    }
}
class RefDemo
{
    static void Main()
    {
        RefTest ob = new RefTest();
        int a = 10;
        Console.WriteLine("a before call: " + a);
        ob.Sqr(ref a); // notice the use of ref
        Console.WriteLine("a after call: " + a);
    }
}

همان‌طور که می‌بینید ref قبل از پارامتر و قبل از argument آمده است و موجب شده که مقدار a بعد از فراخوانی متد تغییر کند.

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

// Swap two values.
using System;
class ValueSwap
{
    // This method now changes its arguments.
    public void Swap(ref int a, ref int b)
    {
        int t;
        t = a;
        a = b;
        b = t;
    }
}
class ValueSwapDemo
{
    static void Main()
    {
        ValueSwap ob = new ValueSwap();
        int x = 10, y = 20;
        Console.WriteLine("x and y before call: " + x + " " + y);
        ob.Swap(ref x, ref y);
        Console.WriteLine("x and y after call: " + x + " " + y);
    }
}

همان‌طور که می‌بینید بعد از فراخوانی متد ()Swap مقدار متغیرهای x و y عوض شده است. نکته‌ی مهم در مورد ref این است که argument ای که از طریق ref ارسال می‌شود باید از پیش تعریف شده باشد. به این دلیل که پارمتر مطمئن شود مقداری که دریافت می‌کند، مقداری معتبر است. بنابراین نمی‌تونید مستقیماً مثلاً مقدار ۱۰ را در argument بنویسید.

out Parameter Modifier

گاهی نیاز دارید که از پارامتر reference استفاده کرده تا مقداری را از یک متد دریافت کنید اما مقداری را به آن ندهید. برای مثال تصور کنید متدی دارید که یک سری عملیات (مثل باز کردن سوکت یک شبکه)را انجام می‌دهد و در نهایت کد موفقیت یا عدم موفقیت را به پارامتر reference باز می‌گرداند. در این‌طور موارد، اطلاعات ارسالی به متد وجود ندارد اما یک‌سری اطلاعات هستند که متد آن‌ها را باز می‌گرداند. مشکل این سناریو این است که ref parameter ابتدا بایستی در یک متغیر مقداردهی اولیه شود بنابراین با استفاده از ref parameter بایستی یک argument با یک مقدار ساختگی (که یک کار بیهوده است) را ارسال کنیم تا به‌اصطلاح دهان compiler را ببندیم که خطایی به برنامه نگیرد. خوشبختانه سی‌شارپ پیشنهاد بهتری برای این مشکل دارد: out parameter

پارامتر out مشابه پارامتر ref است اما یک تفاوت دارد. پارامتر out فقط مقداری را از متد باز می‌گرداند و اطلاعات ارسالی به متد ندارد. نیازی نیست متغیری که به‌عنوان out argument به‌کار می‌رود، در قسمت فراخوانی متد، مقداردهی اولیه شود چراکه متد، خودش یک مقدار را به آن متغیر می‌دهد. علاوه‌براین، درون متد، پارامتر out به‌صورت unassigned در نظر گرفته شده است. بدین معنی که فرض بر این است متغیر مربوطه مقداردهی اولیه نشده است و متد باید خودش مقداری را به متغیر اختصاص دهد. با این تفاسیر بعد از فراخوانی متد، out parameter شامل یک مقدار خواهد بود.

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

class OutExample
{
    static void Method(out int i)
    {
        i = 44;
    }
    static void Main()
    {
        int value;
        Method(out value);
        // value is now 44
    }
}

درون متد Method پارامتر out شامل مقدار ۴۴ است. این مقدار از طریق متغیر i وارد متغیر value می‌شود. همان‌طور که می‌بینید value مقداردهی اولیه نشده و پس از فراخوانی متد، مقدار ۴۴ به آن اختصاص داده شده است.

یکی دیگر از کاربردهای out parameter modifier برای این است که یک متد به‌جای یک خروجی، بتواند چندین خروجی داشته باشد.

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

using System;
class OutReturnExample
{
    static void MyMethod(out int i, out string s1, out string s2)
    {
        i = 180;
        s1 = "I've been returned.";
        s2 = "This example uses out to return three variables.";
    }
    static void Main()
    {
        int i;
        string str1, str2;
        MyMethod(out i, out str1, out str2);
        Console.WriteLine(i);
        Console.WriteLine(str1);
        Console.WriteLine(str2);
    }
}

همان‌طور که می‌بینید از طریق out parameter modifier توانستیم ۳ مقدار را (به‌جای ۱ مقدار) return کنیم. البته اگر return-type متد را به‌جای void مثلاً bool در نظر می‌گرفتیم می‌توانستیم علاوه بر آن سه مقدار، یک مقدار بولین هم برگردانیم و جمعاً ۴ مقدار را return کنیم.

استفاده از ref و out تنها به فرستادن value type ها محدود نمی‌شود بلکه هنگام فرستادن reference نیز می‌توانند مورد استفاده قرار گیرد. این کار به یک متد اجازه می‌دهد تا بتواندreference ای که به شیء‌ای رجوع کرده را تغییر دهدتا به شیء دیگری رجوع کند.در مثال زیر از ref reference parameter استفاده شده تا دو reference که به ۲ شیء جدا رجوع می‌کنند را با هم تعویض کند:

using System;
class MyClass
{
    static void Main()
    {
        Swap swapRef1 = new Swap(2, 3);
        Swap swapRef2 = new Swap(4, 5);

        Console.Write("swapRef1 befor change: ");
        swapRef1.Show();
        Console.Write("swapRef2 befor change: ");
        swapRef2.Show();
        Console.WriteLine();
        swapRef1.swapping(ref swapRef1, ref swapRef2);
        Console.Write("swapRef1 after change: ");
        swapRef1.Show();
        Console.Write("swapRef2 after change: ");
        swapRef2.Show();
    }
}
class Swap
{
    int a, b;
    public Swap(int a, int b)
    {
        this.a = a;
        this.b = b;
    }
    public void swapping(ref Swap ob1, ref Swap ob2)
    {
        Swap t;
        t = ob1;
        ob1 = ob2;
        ob2 = t;
    }
    public void Show()
    {
        Console.WriteLine("a = {0}, b = {1}", a, b);
    }
}

در این مثال، متد ()Swap اشیای argument هایی که به متد پاس داده شده‌اند را با هم تعویض می‌کند. قبل از فراخوانی متد ()Swap متغیر swapRef1 به شیء‌ای با مقادیر ۲ و ۳ ومتغیر swapRef2 به شیء‌ای با مقادیر ۴ و ۵ رجوع می‌کند اما بعد از فراخوانی ()Swap متغیر swapRef1 به شیء‌ای با مقادیر ۴ و ۵ ومتغیر swapRef2 به شیء‌ای با مقادیر ۲ و ۳ رجوع می‌کند. اگر ref را حذف کنید تغییرات اعمال شده فقط درون متد ()Swap می‌ماند و در بیرون از متد تاثیری ندارد.

استفاده از argument به تعداد دل‌خواه

هنگامی‌که یک متد می‌سازید می‌دانید که چه تعداد پارامتر دارید و از آن‌طرف چه تعداد argument قرار است که دریافت کنید اما همیشه قضیه به این صورت نیست. به‌عنوان مثال متدی را در نظر بگیرید که میانگین را حساب می‌کند. آیا همیشه باید ۲ یا ۳ عدد را به آن داده تا میانگین‌شان را بدست آورد؟ مسلماْ نه! این‌چنین متدی باید هر تعداد که argument به آن داده می‌شود میانگین‌اش را بدست آورد و حد و مرزی نداشته باشد. ممکن است یک‌بار به آن ۲ مقدار داده شود، بار دیگر ۳ یا ۷ مقدار داده شود تا میانگین آن‌ها را حساب کند. برای این منظور باید از کلمه‌ی کلیدی params استفاده کنید.params modifier برای تعریف آرایه‌ای از پارامترها به‌کار می‌رود که می‌تواند صفر یا بیشتر از صفر argument را دریافت کند. سایز این آرایه با توجه به تعداد argument هایی که به متد داده شده تعیین می‌شود.

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

using System;
class MyClass
{

    static void Main()
    {
        ParamTest ob = new ParamTest();

        Console.WriteLine(ob.Average(2, 3, 5, 6));
        Console.WriteLine(ob.Average(2, 3.5));

        double[] myArray = { 5, 8, 6, 12, 15.5, 7 };
        Console.WriteLine(ob.Average(myArray));
    }
}
class ParamTest
{
    public double Average(params double[] nums)
    {
        double result = 0;
        for (int i = 0; i < nums.Length; i++)
        {
            result += nums[i];
        }
        return result / nums.Length;
    }
}

به نحوه‌ی استفاده‌یparams در متد ()Average توجه کنید. همان‌طور که می‌بینید در هر بار تعداد متفاوتی از مقادیر نوع double را به متد پاس داده‌ایم و در قسمت آخر آرایه‌ای از جنس double را به متد داده‌ایم تا میانگین آن حساب شود.



نویسنده / مترجم : مسعود درویشیان

علاقه مند به موسیقی و برنامه نویسی بازی


۳۴ دیدگاه برای این نوشته ثبت شده است


  1. حمید
    ۲۱ بهمن ۱۳۹۱

    تشکر و سپاس




  2. mandana
    ۲۲ بهمن ۱۳۹۱

    سلام
    باسپاس وتشکر
    ۱)مهندس حان تاخیر یکم زیاد نشده است در ارایه مطالب ببخشیدا
    ۲)linqوado,netهم آموزش می دهید




    • مسعود درویشیان
      ۲۲ بهمن ۱۳۹۱

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




  3. s.saber
    ۲۵ بهمن ۱۳۹۱

    سلام و خسته نباشد ، واقعا کلاسهای منحصر به فردی ارائه میدهید خیلی جالب اند .
    استاد ببخشید هدفتون از ارائه محیط کنسول سی شارپ چیه ، چرا با محیط ویژوالی کار نمیکنید بهتره ؟؟
    ببخشید درنظر دارید که در آینده محیط ویژوالی سی شارپ را ارائه دهید ؟؟




    • مسعود درویشیان
      ۲۵ بهمن ۱۳۹۱

      سلام. هدف ما از این مجموعه‌ی آموزشی فقط یادگیری اصل زبان سی‌شارپ هست. چون بعد از یادگیری زبان سی‌شارپ دیگه می‌تونید توی محیط‌های دلخواه‌تون (مثل وب، موبایل، بازی و…) ازش استفاده کنید. اون محیط‌ها فقط تکنیک خاص خودشون رو دارن که راحت می‌تونید (توی یه مدت زمان کم) باهاشون آشنا بشید. زبون همون زبون سی‌شارپ هست…




      • s.saber
        ۲۶ بهمن ۱۳۹۱

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




        • مسعود درویشیان
          ۲۶ بهمن ۱۳۹۱

          اگه زمان‌تون خیلی کمه که فکر نمی‌کنم وقت کنید اول اینو یاد بگیرید بعد توی یه محیط ویژوال پروژه پیاده کنید. (البته همه‌چیز بستگی به خودتون و زمان‌تون داره)
          اما اگه بخواین یه پروژه مثل “انتخاب واحد دانشجو” یا “آژانس” یا برنامه‌هایی در این سطح رو توی محیط کنسول پیاده کنید فعلاً تا همین قسمت رو بخونید می‌تونید انجام بدید.




          • s.saber
            ۲۷ بهمن ۱۳۹۱

            ممنون از پاسختون ، خب فرصت تا ۳۰ خرداده و پروژه ام سیستم حسابداری دانشگاست ، بنظرتو چکار کنم ؟؟
            ممنون




          • مسعود درویشیان
            ۲۷ بهمن ۱۳۹۱

            اگه تا ۲ ماه آینده زنگ سی‌شارپ رو دنبال کنید (و واقعاً یاد بگیرید و تمرین کنید) و اون یکی ۲ ماه آخر هم توی یه محیط ویژوال تمرین کنید به احتمال زیاد می‌تونید پروژه رو انجام بدید. اما بازم می‌گم، همه‌چی بستگی به (تمرین) خودتون داره…




  4. مهدی
    ۲۶ بهمن ۱۳۹۱

    سلام و خسته نباشید آقای درویشیان؛
    منظور شما از این مبحث گفته هاتون چیه:
    “متد ()SameAs مقادیر Name، Surname و Age را از متدی که فراخوانی شده با مقادیر Name، Surname و Age شیء ob که به متد داده شده است، ”
    یعنی چی؟ وقتی که خودش متد هست به چه نحوه دیگه ای توسط متدی دیگر فراخوانی می شود؟ لطفا مبسوط تر توضیح بدید.




    • مسعود درویشیان
      ۲۶ بهمن ۱۳۹۱

      متد ()SameAs کارش اینه که یه شیء می‌گیره، فیلدهای شیءای رو که گرفته با فیلدهای همون شیء‌ای که متد ()SameAs از اون داره صدا زده می‌شه، مقایسه می‌کنه (یعنی فیلدهای ۲ تا شیء رو مقایسه می‌کنه) اگه برابر بود که true اگرم نه که false برمی‌گردونه




      • مهدی
        ۲۷ بهمن ۱۳۹۱

        در واقع پارامترهاش فیلدهای یک کلاس هستند(در متد ()SamesAs )
        در متد Copy و در این خط ;( ob1.Copy(ob در واقع فیلدهای ob1 ریخته میشن تو ob ؟
        طبق این خطوط:
        Name = ob.Name;
        Surname = ob.Surname;
        Age = ob.Age;




        • مسعود درویشیان
          ۲۷ بهمن ۱۳۹۱

          نه! همیشه سمت راست مساوی ریخته می‌شه توی سمت چپ مساوی یعنی فیلدهای ob ریخته‌ می‌شوند توی ob1




  5. داوود
    ۴ اسفند ۱۳۹۱

    سلام آقا مسعود؛ وقتت بخیر
    مسعود جان در این عبارت که نوشتید:
    “در این مثال، متد ()Swap اشیای argument هایی که به متد پاس داده شده‌اند را با هم تعویض می‌کند.”
    آیا به جای متد swap نباید می نوشتید متد swapping ؟ آخه متد swap که فقط کار مقدار گذاری رو داره انجام میده؟؟
    همچنین میشه بگید این خط دقیقاً چه کاری انجام میده؟
    [C#]Swap t [/C#]




    • مسعود درویشیان
      ۵ اسفند ۱۳۹۱

      آره ببخشید اشتباه نوشتم :) swapping درسته
      Swap t هم که مثل یه متغیر واسط هست برای جابه‌جایی اون دو مقدار دریافتی…




  6. محمد فر
    ۱۹ فروردین ۱۳۹۲

    سلام.در مورد مثال اول سئوال داشتم:
    چرا تو متد از کلمه this استفاده نکردید؟
    مثلا توی متذ sameAs()




    • مسعود درویشیان
      ۱۹ فروردین ۱۳۹۲

      چون نیازی نبوده! وقتی می‌نویسیم Name، مگر چندتا فیلد Name توی اون کلاس (MyClass) وجود داره؟ فقط یکی!
      اما وقتی می‌خوایم به فیلد Name شیء ob که به متد ()SameAs داده شده دسترسی داشته باشیم، از طریق ob.Name بهش دسترسی داریم. ولی اگه بنویسیم Name یا this.Name منظورمون فیلد Name همین کلاسی است که الان داخلشیم (که می‌شه فیلد Name شیءای که از روی این کلاس می‌سازی و ازش استفاده می‌کنی)
      اگه مشکلی بود بگین تا واضح‌تر بگم




  7. محمد فر
    ۲۱ فروردین ۱۳۹۲

    با تشکر از توضیحاتتون.متوجه شدم




  8. محمد فر
    ۲۱ فروردین ۱۳۹۲

    سلام استاد.
    در مورد مثال swap که نوشتید سئوال داشتم.
    من تا الان فکر می کردم اگه یه شی رو به یک متد پاس کنیم ادرس شی درون پارامتر شی کپی میشه.مثلا ما یه شی می سازیم به این صورت:
    Swap swapRef1;
    در اینجا ما یه متغییر از نوع swap تعریف کردیم.یعنی swapRef1 داره به یک مکانی از حافظه اشاره میکنه یعنی یک اشاره گر است.حالا ما در خط بعدی به swapRef1 حافظه اختصاص می دهیم(یعنی به member هاش)
    swapRef1 = new Swap(2, 3);
    حالا چیزی که من برداشت کردم اینه که وقتی این شی رو به متد swapping می فرستیم ادرس این شی است که درون پارامتر b1 یا b2 این متد ریخته میشه. در این خط این اتفاق می افتد:
    swapRef1.swapping(swapRef1,swapRef2);
    یعنی با اجرا این خط b1 ادرس swapRef1 را در خودش دارد یعنی دارد به این شی اشاره می کند و b2 هم به swapRef2.
    با این توضیحات من متوجه نشدم که چه نیازی به استفاده از کلمه کلیدی ref در متد می باشد.خلاصه کلام مگر یک class یک refrence type نمی باشد پس باید شامل دو قسمت باشد یکی ادرس و دیگری مقدار.
    امیدورام متوجه سئوالم شده باشید.می بخشید که زیاد نوشتم.




    • مسعود درویشیان
      ۲۳ فروردین ۱۳۹۲

      آره این آدرس شیء هست که جابه‌جا می‌شه
      اگر از ref استفاده نکنی، آدرس این دو شیءای که ساختی و پاس دادی به متد، با هم تعویض نمی‌شه. یعنی نمی‌ره این آدرس‌ها رو از reference تغییر بده!




  9. محمد فر
    ۲۳ فروردین ۱۳۹۲

    میشه بیشتر توضیح بدید.متوجه نشدم




    • مسعود درویشیان
      ۲۸ فروردین ۱۳۹۲

      ببین محمد جان، اگه دقت کنی ما به دو طریق argument ها رو به پارامترها می‌فرستیم: call-by-value و call-by-reference
      که call-by-value برای value type ها هست (مثل int و double و…) و call-by-reference برای reference type ها (مثل اشیایی که خودت تعریف می‌کنی)
      پس اگه یه عدد (مثلاً از جنس int) رو به پارامترها بفرستی داری از روش call-by-value استفاده می‌کنی که موجب می‌شه هر تغییری توی متد (روی عددی که گرفتی) انجام بدی، این تغییر توی همون متد بمونه و روی همون پارامتر اعمال بشه. چرا؟؟؟ چون وقتی از روش call-by-value استفاده می‌کنی یه کپی از argument به parameter داده می‌شه و توی متد همین کپی‌ای رو که داره تغییر می‌ده و دیگه کاری به اون متغیر اصلی (argument) نداره. حالا اگه می‌خوای تغییراتی که روی پارامتر اعمال می‌کنی، روی argument هم اعمال بشه، از ref استفاده می‌کنی.

      ولی اگه یه reference رو پاس بدی داری از call-by-reference استفاده می‌کنی یعنی مستقیماً می‌تونی مقادیر یه شیء رو تغییر بدی. اما توی این مورد swap که قرار آدرس دوتا شیء رو جابه‌جا کنی به ref نیاز داری چون به مقدار داخل شیء کاری نداری و صرفاً داری آدرس‌شون رو جابه‌جا می‌کنی




  10. محمد فر
    ۲۴ فروردین ۱۳۹۲

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



    • تا اونجا که من متوجه شدم، دو کلیدواژه ref و out برای call-by-reference بی تاثیر هست. (من تست کردم با ref و هردو با اون یا بدونه اون مقدار شیء تغییر میکنه). اینطوری برداشت کردم که چون قبلا هم گفته شده که reference وقتی میدی خود شیء رو نمیدی بلکه آدرسش رو میدی. پس شیء سر جاش هست و هر تغییری از طریق آدرس صورت بگیره روی شیء مستقیما تاثیر میذاره. اکر مثلا اینطوری بود که شیء رو میداد یا یه کپی از شیء میگیرفت و آدرس کپی رو میداد اونوقت استفاده از out و ref مخصوصا معنا میگرفت. (البته به این گفته های خودم شک دارم)
      دو کلیدواژه برای call-by-value معنی دارن که یه کپی از مقدار همیشه به آرگومان داده میشه. وقتی تغییری ایجاد کنی روی کپی داری تغییر میدی. واسه اینکه روی اصلی تغییر ایجاد کنی باید از ref یا out بسته به نیازت استفاده کنی.

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




  11. Mersad
    ۲۶ مرداد ۱۳۹۲

    سلام جناب درویشیان
    من مقاله ی شما رو به همراه کامنت هاش چندبار خوندم و مثال هاشو چندبار تمرین کردم ولی بنده هم ابهام آقای محمدفر و آقای اسکندری پور برام بوجود اومده.

    مگه وقتی شی رو به یک متد میفرستیم، خودش call-by-reference نیست؟ دیگه چه نیازی به کلمه ی ref هست؟
    منظورم اینه که وقتی یک شی رو میفرستیم، یه کپی ازش رو که نمیفرسته، بلکه آدرس اون شی رو میفرسته، و حالا با استفاده از آدرسش، هر تغییری که ایجاد کنیم، روی اون شی و در نتیجه روی argument هم ایجاد میشه.

    حالا با این تفاسیر چرا برای ارسال argumnet هایی که شی هستن (حاوی آدرس شی هستن) باید از ref استفاده کنیم؟
    تو مواردی که الان بیان کردم، کدوم قسمتش غلط هست که نمیتونم مثال Swap رو درک کنم که چرا وقتی ref رو برمیداریم جابجایی اشیا اتفاق نمیوفته؟

    خیلی ممنون




    • مسعود درویشیان
      ۳ شهریور ۱۳۹۲

      ببینید ما قرار نیست توی اون مثال بیایم محتوای اشیاء رو تغییر بدیم. ما دوتا شیء داریم که می‌خواهیم فقط آدرس‌هاشون رو با هم عوض کنیم. همین! واسه این‌که آدرس‌هاشون هم جابه‌جا کنیم به ref نیاز داریم چون در غیر این‌صورت تغییرات توی همون متد باقی می‌مونه




  12. a-p
    ۱۵ مرداد ۱۳۹۳

    بسم الله الرحمن الرحیم
    سلام
    می توانید توضشح و مثال بیشتری در مورد outبزنید




  13. داود چهریان
    ۲۰ آذر ۱۳۹۳

    سلام استاد درویشیان
    واقعا توضیحات عالی و کامل هستند
    تشکر فراوان از شما




  14. komeil asadi
    ۲۳ آذر ۱۳۹۳

    salam ostad, vaghan behtar az har kelasi tozih midid.
    tashakor az zahamate shoma




  15. rahimi
    ۲۵ آذر ۱۳۹۳

    سلام ممنونم بابت آموزش های کامل و مفیدتون…فقط یه سوال من هر چی گشتم آموزش توابع رو پیدا نکردم خیلی بهش احتیاج دارم توی کدوم قسمت توابع آموزش داده شده؟؟؟
    یه سوال دیگه:توی توابع از کجا باید بفهمیم بازگشتی هست یا نه؟؟یا چه موقع از void باید استفاده کنیم؟؟




    • محمد
      ۱ مهر ۱۳۹۴

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




  16. سارا
    ۲۳ دی ۱۳۹۳

    مرسی عالی بود




  17. مری
    ۳ مرداد ۱۳۹۴

    استاد مگه string شامل ریفرنس ها نمیشد ؟ پس چرا ارگومان تغیر نمیکنه ؟




  18. علي
    ۳۱ اردیبهشت ۱۳۹۵

    با سلام.من یک ماتریس ٢بعدی تعریف کرده ام که دائم در حال تغییر است.در حِین تغییر این ماتریس را ذخیره میکنم.ولی در آخر که به این ماتریس های ذخیره شده رجوع میکنم همگی برابر ماتریس کنونی است.اگر میشود راهنمایی کنید



دیدگاه خود را بنویسید





نشانی ایمیل شما منتشر نخواهد شد.

کامنت های شما بعد از تأیید توسط نویسنده وبلاگ، منتشر خواهند شد.

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

شما میتوانید با مراجعه به سایت گراواتار یک آواتار اختصاصی برای خود تعریف کنید، تا در کنار نام شما نمایش داده شود

برای قرار دادن کدهای نمونه می توانید از تگ های [php] ، [html] ، [css] و [js] استفاده کنید.
به عنوان مثال کدهای php را می توان به صورت زیر قرار داد:
[php] var $whoLoveIranians = "WebTarget!"; [/php]



کلیه حقوق مادی و معنوی برای وب سایت وب تارگت محفوظ است ©2017 webtarget.ir

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