PDA

View Full Version : مبتدی: ارسال یک شی از کلاس به عنوان آرگومان متد



karimi72
شنبه 12 مرداد 1392, 12:17 عصر
دوستان عزیز
با یک مثال سوالم را شروع می کنم تا بهتر متوجه شوید :
اگر ما یک int را به صورت عادی (نه با ref , out ) به یک متد ارسال کنیم هر تغییری در متغییر دهیم در متغییر اصلی هیچ تغییری رخ نمی دهد .
حال سوالم این جاست که اگر یک شی را به صورت عادی بفرستیم اگر در متغییر های شی تغییر ایجاد کنیم این تغییرات ماندنی هستند یا مثل int که ابتدا مثال زدیم موقتی ؟

Amin69
شنبه 12 مرداد 1392, 12:27 عصر
دوستان عزیز
با یک مثال سوالم را شروع می کنم تا بهتر متوجه شوید :
اگر ما یک int را به صورت عادی (نه با ref , out ) به یک متد ارسال کنیم هر تغییری در متغییر دهیم در متغییر اصلی هیچ تغییری رخ نمی دهد .
حال سوالم این جاست که اگر یک شی را به صورت عادی بفرستیم اگر در متغییر های شی تغییر ایجاد کنیم این تغییرات ماندنی هستند یا مثل int که ابتدا مثال زدیم موقتی ؟
سلام دوست عزیز؛
بهترین راه به جواب رسیدن، آزمایش هست؛ قبل از اینکه من آزمایش کنم، بهتره که خدا شما آزمایش کنید!
یا علی

amir200h
شنبه 12 مرداد 1392, 12:34 عصر
دوستان عزیز
با یک مثال سوالم را شروع می کنم تا بهتر متوجه شوید :
اگر ما یک int را به صورت عادی (نه با ref , out ) به یک متد ارسال کنیم هر تغییری در متغییر دهیم در متغییر اصلی هیچ تغییری رخ نمی دهد .
حال سوالم این جاست که اگر یک شی را به صورت عادی بفرستیم اگر در متغییر های شی تغییر ایجاد کنیم این تغییرات ماندنی هستند یا مثل int که ابتدا مثال زدیم موقتی ؟

فقط در همون حیطه (بهتربگم نامی که برای ساخت از اون کلاس استفاده کردی) تغییر میکنه و تا وقتی نابود نشه این تغییرات پایدارن

Amin69
شنبه 12 مرداد 1392, 12:47 عصر
بله... طبق آزمایش انجام شده(!)، شما حتی اگه اون شی رو بصورت معمولی به یک متد بفرستید، هر تغییری که روی اون شی انجام بشه، روی شی اصلی هم انجام میشه.
اینم نمونه کد آزمایشی:

class Program
{
static void Main(string[] args)
{
test t = new test(); // t.x = 0
method(t, 5); // t.x = 5
method(t, 10); // t.x = 10
}
static void method(test obj, int b)
{
obj.x = b;
}
}
class test
{
public int x;
public test()
{
x = 0;
}
}

یا علی

karimi72
شنبه 12 مرداد 1392, 19:40 عصر
سلام دوست عزیز؛
بهترین راه به جواب رسیدن، آزمایش هست؛ قبل از اینکه من آزمایش کنم، بهتره که خدا شما آزمایش کنید!
یا علی
از پاسخ شما بسیار ممنونم و این موضوع را آزمایش کردم ولی شک داشتم همیشه این طوری است .
حال این موضوع برای زمانی که به عنوان یک شی ref هم ارسال شود بر قرار است نکته ی مهمی نیست که باید به آن توجه کرد ؟

مهرداد صفا
شنبه 12 مرداد 1392, 23:03 عصر
دوستان عزیز
با یک مثال سوالم را شروع می کنم تا بهتر متوجه شوید :
اگر ما یک int را به صورت عادی (نه با ref , out ) به یک متد ارسال کنیم هر تغییری در متغییر دهیم در متغییر اصلی هیچ تغییری رخ نمی دهد .
حال سوالم این جاست که اگر یک شی را به صورت عادی بفرستیم اگر در متغییر های شی تغییر ایجاد کنیم این تغییرات ماندنی هستند یا مثل int که ابتدا مثال زدیم موقتی ؟

با سلام.
با توجه به مطالبی که در این (http://barnamenevis.org/showthread.php?405697-%D9%85%D8%AA%D8%BA%DB%8C%DB%8C%D8%B1-Reference-Type-%D9%88-Value-Type-%DA%86%DB%8C%D8%B3%D8%AA%D8%9F) تاپیک گفتم در حالت ارسال ByVal یا ارسال معمولی، مقدار متغیر های Value type در آدرسی که برای آرگومنت متود در نظر گرفته شده، کپی می شود، در نتیجه هر تغیر که در پارامتر ارسال شده اعمال شود مربوط به یک آدرس مجزا و یک متغیر مجزا بوده و هیچ تاثیری روی متغیر اصلی ندارد. اما متغیر های reference type (همونطور که در تاپیک بالا اشاره شد) صرفا یک اشاره گر هستند و آدرس مقادیر واقعی را در خود نگه می دارند.
اما وقتی که یک متغیر reference type به عنوان یک پارامتر و به صورت byval ارسال می شود چه اتفاقی می افتد؟
فرض می کنیم که b آرگومنت یک متودی است که ما aرا به آن ارسال می کنیم و a و b هر دو reference type هستند. در این حالت آدرسی که متغیر a به آن اشاره می کند در متغیر b کپی می شود. در واقع در این حالت a و b دو متغیر جداگانه هستند ولی هر دو اینها به یک خانه اشاره می کنند. درک این نکته خیلی مهم است که بدانیم در این حالت a و b دقیقا یکی نیستند ولی هر دو به یک مقدار اشاره می کنند. حالا مثلا اگر نوع این پارامتر یک لیست باشد و ما با استفاده از متود
b.Add("x"); یک عضو به این لیست اضافه کنیم این تغییرات در متغیر a هم اعمال می شود چرا که همانطور که گفته شد هر دو به یک آدرس اشاره می کنند.
پس در این حالت تفاوت ارسال ByVal و ByRef در مورد متغیر های reference type چیست؟
همانطور که گفتیم در حالت byVal و در مثال قبلی a و b دقیقا یکی نبودند ولی به یک آدرس یکسان اشاره می کردند و اگر ما خصوصیتی از b را تغییر می دادیم این تغییر در a نیز اعمال می شد. حالا به نظر شما اگر ما در طول اجرای متود یک آدرس جدید در b قرار بدهیم چه اتفاقی می افتد؟


//b=new address...
b=new List<String>();
آیا آدرس متغیر a هم تغییر میکند؟
پاسخ منفی است. چون که در حالت ByVal a و b دو متغیر جدا بودند که به یک آدرس اشاره می کردند، پس اگر b به یک آدرس جدید اشاره کند a کماکان به آدرس قبلی اشاره می کند. در واقع در حالت ByVal و بعد از تغییر آدرس b کد زیر هیچ تغییری در a ایجاد نمی کند:


b.Add("y");

حالا c را آرگومنتی فرض کنید که ما d را به ازای آن به صورت ref ارسال می کنیم. در این حالت خود d دقیقا به c ارسال می شود و d و c یک متغیر هستند با دو نام. پس اگر c تغییر کند و یا حتی اگر به طور کلی یک شی جدید در c قرار بگیرد و آدرسش تغییر کند، تمام این تغیرات در d هم اتفاق خواهد افتاد. در واقع c در این حالت یک اشاره گر به اشاره گر یا همان چیزی است که در زبان c++ به آن
**c گفته می شد.

نتیجه گیری کلی:
1- در حالت ByVal تغییراتی که در آرگومنت داده می شود در متغیر اصلی هم اثر دارد:


void xxx (List<String> b)
{
b.Add("x");
}

List<String> a=new List<String>();
xxx(a);
MessageBox(a.Contains("x"));//true

3- در حالت ByVal اگر آرگومنت به یک شی دیگر اشاره کند ماهیت متغیر اصلی تغییر نمی کند:


void xxx2( List<String> b)
{
b=new List<String>();
b.Add("x");
}
///...
List<String> a=New List<String>();
xxx2(a);
MessageBox.Show(a.Contains("x").ToString());//false

3- در حالت ref هر تغییری که روی آرگومنت اعمال شود روی متغیر اصلی موثر است:


void xxx3(ref List<string> c)
{
c.Add("x");
}
//....
List<String> d=new List<String>();
xxx3(ref d);
MessageBox.Show(d.Contains("x").ToString());//true


4- درحالت ref هر تغییری که در ماهیت آرگومنت اتفاق بیفتد و حتی اگر آرگومنت به شی جدیدی اشاره کند تغییرات در متغیر اصلی موثر است:


void xxx4(ref List<String> c)
{
c=new List<String>();
c.Add("x");
}
//...
List<string> d=new LIst<String>();
MessageBox.Show(d.Contains("x").ToString());//true