PDA

View Full Version : سوال: سوال در مورد ارسال آرگومان به روش ارجاع (ref)



ProUnity
شنبه 13 تیر 1394, 20:42 عصر
سلام دوستان این اولین پست من در این انجمن هست و به تازگی دارم با خوندن کتابی C# رو یاد میگیرم.

خب سوال من :

اینطور که من متوجه شدم اگر هنگام تعریف آرگومان برای متد از کلمه کلیدی ref استفاده کنیم کلیه عملیاتی که داخل متد روی ورودی ref انجام میشه در خارج از اون هم اعمال میشه مثلا کد زیر :

public class Program {
static void IncrementElement(int number)
{
number++;
}


public static void Main()
{
int num = 5;


Console.WriteLine(num);


IncrementElement(num);


Console.WriteLine(num);
}
}

مثلا در کد بالا هر دوبار 5 چاپ میشه (با اینکه داخل متدمون بهش یدونه اضافه کردیم)


public class Program {
static void IncrementElement(int number)
{
number++;
}


public static void Main()
{
int num = 5;


Console.WriteLine(num);


IncrementElement(ref num);


Console.WriteLine(num);
}
}

اما الان دیگه این اتفاق نمیفته و یکبار 5 و بار دیگه 6 چاپ میشه تا اینجا سوالی ندارم اما وقتی یک آرایه رو به عنوان ورودی متد در نظر میگیرم حتی اگر از ref استفاده نکنم بازم هر تغییری روی آرایه در خارج از اون هم اعمال میشه و سوالم اینه که چرا وقتی ما از ref استفاده نکردیم هر تغییری روی آرایه داخل متد در خارج از اون هم اعمال میشه؟؟

public class Program {
static void IncrementElements(int[] numbers)
{
for (int i = 0; i < numbers.Length; i++)
{
numbers[i]++;
}
}


public static void Main()
{
int[] array = { 1 , 2, 3, 4, 5};


IncrementElements(array);


foreach (int num in array)
{
Console.WriteLine(num);
}
}
}

مثلا اینجا به جای اینکه 1 2 3 4 5 چاپ بشه 2 3 4 5 6 چاپ میشه و سوالم اینه که چرا اینطور میشه (چون از کلمه کلیدی ref استفاده نکردیم پس نباید اینطور بشه) و چجوری میشه کاری کرد که آرایه در خارج متد تغییر نکنه .



باتشکر

ProUnity
یک شنبه 14 تیر 1394, 14:18 عصر
دوستان انجمن خلوته یا کسی تایپک رو ندیده؟:اشتباه:

tefos666
یک شنبه 14 تیر 1394, 14:23 عصر
using System;

class Program
{
static void Main()
{
int val = 0;

Example1(val);
Console.WriteLine(val); // Still 0!

Example2(ref val);
Console.WriteLine(val); // Now 2!

Example3(out val);
Console.WriteLine(val); // Now 3!
}

static void Example1(int value)
{
value = 1;
}

static void Example2(ref int value)
{
value = 2;
}

static void Example3(out int value)
{
value = 3;
}
}



Output

0
2
3

http://barnamenevis.org/showthread.php?398105-%D9%85%DB%8C%D8%B4%D9%87-%D8%AF%D9%84%DB%8C%D9%84-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D9%BE%D8%A7%D8%B1%D8%A7%D9%85%D8%AA%D8%B1%D9%87%D 8%A7%DB%8C-ref-%D9%88-out-%D8%B1%D9%88-%D8%AA%D9%88%D8%B6%DB%8C%D8%AD-%D8%A8%D8%AF%DB%8C%D8%AF%D8%9F

http://www.webtarget.ir/blog/%D8%B2%D9%86%DA%AF-%D8%B3%DB%8C%E2%80%8C%D8%B4%D8%A7%D8%B1%D9%BE-
%D9%82%D8%B3%D9%85%D8%AA-%D8%A8%DB%8C%D8%B3%D8%AA-%D9%88-%D9%BE%D9%86%D8%AC%D9%85-25/ (http://www.webtarget.ir/blog/%D8%B2%D9%86%DA%AF-%D8%B3%DB%8C%E2%80%8C%D8%B4%D8%A7%D8%B1%D9%BE-%D9%82%D8%B3%D9%85%D8%AA-%D8%A8%DB%8C%D8%B3%D8%AA-%D9%88-%D9%BE%D9%86%D8%AC%D9%85-25/)

ProUnity
یک شنبه 14 تیر 1394, 14:37 عصر
دوست عزیز ممنون اما انگار شما متوجه سوال من نشدین من میدونم ref چیه سوالی که دارم اینه که چرا برای آرایه ها عمل نمیکنه

tefos666
یک شنبه 14 تیر 1394, 14:43 عصر
عمل میکنن


مثال خود مایکروسافت

class TestRef
{
static void FillArray(ref int[] arr)
{
// Create the array on demand:
if (arr == null)
{
arr = new int[10];
}
// Fill the array:
arr[0] = 1111;
arr[4] = 5555;
}

static void Main()
{
// Initialize the array:
int[] theArray = { 1, 2, 3, 4, 5 };

// Pass the array using ref:
FillArray(ref theArray);

// Display the updated array:
System.Console.WriteLine("Array elements are:");
for (int i = 0; i < theArray.Length; i++)
{
System.Console.Write(theArray[i] + " ");
}

// Keep the console window open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}



/* Output:
Array elements are:
1111 2 3 4 5555
*/

https://msdn.microsoft.com/en-us/library/szasx730.aspx

CrafteR
یک شنبه 14 تیر 1394, 15:46 عصر
مثلا اینجا به جای اینکه 1 2 3 4 5 چاپ بشه 2 3 4 5 6 چاپ میشه و سوالم اینه که چرا اینطور میشه (چون از کلمه کلیدی ref استفاده نکردیم پس نباید اینطور بشه) و چجوری میشه کاری کرد که آرایه در خارج متد تغییر نکنه .



جواب سوال شما مربوط میشه به مفهوم ValueType ها و ReferenceType ها.
کتابی که دارین مطالعه میکنید به این دو مفهوم اشاره ای کرده ؟

jeson_park
یک شنبه 14 تیر 1394, 15:55 عصر
دوست عزیز
دو نوع ارسال داده به تابع داریم

pass by value
pass by Reference

در سی شارپ وقتی یه مقدار رو به تابع می فرستین به صورت pass by value ارسال می شه (یعنی یه کپی از اون مقدار به تابع داده می شه و در نتیجه اگه تابع اون مقدار رو دستکاری کنه تغییری در مقدار اصلی داده نمی شه )
اما آرایه ها از نوع pass by Reference هستن (بعنی کپی مقدارشون به تابع فرستاده نمی شه بلکه آدرسش فرستاده می شه)
در نتیجه هر تغییری در آرایه درون تابع ،روی آرایه اصلی هم اعمال می شه

CrafteR
یک شنبه 14 تیر 1394, 16:05 عصر
در سی شارپ وقتی یه مقدار رو به تابع می فرستین به صورت value type ارسال می شه (یعنی یه کپی از اون مقدار به تابع داده می شه و در نتیجه اگه تابع اون مقدار رو دستکاری کنه تغییری در مقدار اصلی داده نمی شه )

value type ها ربطی به مقدار ارسالی به تابع نداره فکر کنم دارین اشتباه میگید. منبع این حرف شما کجاست؟
همینطور که از اسمش مشخصه "نوع های داده" هستند که این خاصیت دارند و ربطی به این نداره که به تابع فرستاده بشند یا نه.

jeson_park
یک شنبه 14 تیر 1394, 16:15 عصر
value type ها ربطی به مقدار ارسالی به تابع نداره فکر کنم دارین اشتباه میگید. منبع این حرف شما کجاست؟
همینطور که از اسمش مشخصه "نوع های داده" هستند که این خاصیت دارند و ربطی به این نداره که به تابع فرستاده بشند یا نه.
ببخشید منظورم pass by value و pass by
Reference هستش

khokhan
یک شنبه 14 تیر 1394, 16:17 عصر
.............................................


static void Method(ref int i)
{

i = i + 44;
}

static void Main()
{
int val = 1;
Method(ref val);
Console.WriteLine(val);


}

CrafteR
یک شنبه 14 تیر 1394, 16:20 عصر
.............................................


static void Method(ref int i)
{

i = i + 44;
}

static void Main()
{
int val = 1;
Method(ref val);
Console.WriteLine(val);


}

جواب شما نامربوط به سواله!!!!!
لطفا اول سوال کامل بخونید

ProUnity
یک شنبه 14 تیر 1394, 18:01 عصر
دوست عزیز
دو نوع ارسال داده به تابع داریم

pass by value
pass by Reference

در سی شارپ وقتی یه مقدار رو به تابع می فرستین به صورت pass by value ارسال می شه (یعنی یه کپی از اون مقدار به تابع داده می شه و در نتیجه اگه تابع اون مقدار رو دستکاری کنه تغییری در مقدار اصلی داده نمی شه )
اما آرایه ها از نوع pass by Reference هستن (بعنی کپی مقدارشون به تابع فرستاده نمی شه بلکه آدرسش فرستاده می شه)
در نتیجه هر تغییری در آرایه درون تابع ،روی آرایه اصلی هم اعمال می شه

آها خیلی ممنون همین جوابی بود که میخواستم حالا اگر نخوام آرایه ها pass by reference بشن (و pass by value)باید یه کپی بگیرم از آرایه و توی یک آراهی دیگه بریزم؟ یا راه دیگه ای داره ؟

با تشکر از همه‌ی دوستان و سایر پاسخگو ها

elec60
یک شنبه 14 تیر 1394, 19:09 عصر
فکر میکنم یه متد هست که آرایه رو ReadOnly میکنه، شاید به درد بخوره

برای کپی هم بهتره از متد Clone استفاده کنی

elec60
یک شنبه 14 تیر 1394, 19:13 عصر
یه چیز دیگه در مورد ref اضافه کنم:
اگه به یک متد با آرگومان ref یک آرایه پاس بدین در واقع در stack خانه جدیدی برای ذخیره کردن آدرس آرایه ایجاد نمیشه و هر دو متغییر داخل و بیرون متد در واقع یکی هستند. و اگه متغییر داخل متد رو null کنین بعد از اجرای متد دیگه به متغیر بیرونی هم دسترسی نخواهید داشت.

jeson_park
دوشنبه 15 تیر 1394, 11:33 صبح
آها خیلی ممنون همین جوابی بود که میخواستم حالا اگر نخوام آرایه ها pass by reference بشن (و pass by value)باید یه کپی بگیرم از آرایه و توی یک آراهی دیگه بریزم؟ یا راه دیگه ای داره ؟

با تشکر از همه‌ی دوستان و سایر پاسخگو ها
دوست عزیز آرایه reference type هست و نمی شه به عنوان Value Type استفاده بشه اما خود کلاس آرایه یه متد به نام AsReadOnly داره که توضیحات MSDN گفته :

.
To prevent any modifications to the array, expose the array only through this wrapper.

نمونه کد

String[] myArr = { "The", "quick", "brown", "fox" };
....
// Print array
....
IList<String> myList = Array.AsReadOnly( myArr );


....
// Print array
....


//Try To Change it!
try {
myList[3] = "CAT";
}
catch ( NotSupportedException e ) {
Console.WriteLine( "{0} - {1}", e.GetType(), e.Message );
Console.WriteLine();
}

یا همونطور که دوستان گفتن از Array.Clone (https://msdn.microsoft.com/en-us/library/system.array.clone.aspx) استفاده کنی

و یا کلاً بیخیال آرایه شو و کد رو تغییر بده!:لبخند: