آموزش پارامترهای مرجع(reference) در سی شارپ
تمام تابع هایی که تا اینجا تعریف کرده ایم، پارامترهایی از نوع مقدار داشته اند. یعنی وقتی که از پارامترها استفاده کرده ایم، یک مقدار(value) را در یک متغیر که توسط این تابع استفاده می شود، پاس داده ایم. هر تغییری که در این متغیر در تابع مورد نظر داده شود، تاثیری روی آرگومان های مشخص شده در فراخوانی این تابع ندارد. بعنوان مثال، یک تابع را در نظر بگیرید که مقدار یک پارامتر پاس داده شده را دو برابر می کند و نمایش می دهد:
static void ShowDouble(int val)
{
val *= 2;
WriteLine($"val doubled = {val}");
}
در اینجا، پارامتر مورد نظر یعنی val ،در این تابع دو برابر شده است. اگر آن را به صورت زیر فراخوانی کنیم،
int myNumber = 5;
WriteLine($"myNumber = {myNumber}");
ShowDouble(myNumber);
WriteLine($"myNumber = {myNumber}");
آنگاه خروجی متنی در کنسول به صورت زیر خواهد بود:
myNumber = 5
val doubled = 10
myNumber = 5
فراخوانی ShowDouble() با myNumber بعنوان یک آرگومان، تاثیری بر مقدار myNumber در Main() ندارد، با اینکه پارامتری که به آن انتساب داده شده است، یعنی val دو برابر شده است. همه ی اینها خیلی خوب است، اما اگر می خواهید مقدار myNumber تغییر کند، یک مشکل وجود دارد. ما می توانستیم از یک تابع استفاده کنیم که یک مقدار را برای myNumber برگرداند، مانند زیر:
static int DoubleNum(int val)
{
val *= 2;
return val;
}
ما می توانستیم این تابع را با استفاده کدهای زیر فراخوانی کنیم:
int myNumber = 5;
WriteLine($"myNumber = {myNumber}");
myNumber = DoubleNum(myNumber);
WriteLine($"myNumber = {myNumber}");
اما این کد، به سختی قابل درک است و از عهده ی تغییر مقادیر چند متغیر به کار رفته بعنوان آرگومان برنمی آید(زیرا تابع ها تنها یک مقدار برگشتی دارند). به جای آن، می توانیم این پارامتر را توسط مرجع(by reference) پاس دهیم؛ یعنی اینکه این تابع دقیقاً با همان متغیری که در فراخوانی این تابع استفاده شده است، کار کند؛ نه فقط با یک متغیر که مقدار مشابهی دارد.
هر تغییری که در این متغیر داده شود، در مقدار متغیری که بعنوان آرگومان استفاده شده است، منعکس می شود. برای انجام این کار، به سادگی می توانیم از کلمه ی کلیدی ref برای مشخص کردن این پارامتر استفاده کنیم:
static void ShowDouble(ref int val)
{
val *= 2;
WriteLine($"val doubled = {val}");
}
سپس، آن را دوباره در فراخوانی تابع مشخص می کنیم(این اجباری است):
int myNumber = 5;
WriteLine($"myNumber = {myNumber}");
ShowDouble(ref myNumber);
WriteLine($"myNumber = {myNumber}");
خروجی متنی در کنسول به صورت زیر خواهد بود:
myNumber = 5
val doubled = 10
myNumber = 10
به دو محدودیت در متغیری که بعنوان پارامتر ref استفاده شده اند توجه کنید. اول اینکه، تابع مورد نظر ممکن است منجر به ایجاد یک تغییر در مقدار یک پارامتر مرجع(reference parameter) شود، بنابراین باید در فراخوانی این تابع از یک متغیر غیر ثابت(non constant) استفاده کنید؛ بنابراین کد زیر غیرقانونی است:
const int myNumber = 5;
WriteLine($"myNumber = {myNumber}");
ShowDouble(ref myNumber);
WriteLine($"myNumber = {myNumber}");
دوم اینکه، ما باید از یک متغیر که مقداردهی اولیه(initialized) شده باشد استفاده کنیم. سی شارپ به ما اجازه نمی دهد تا فرض کنیم که یک پارامتر ref در تابعی که از آن استفاده می کند، مقدار دهی اولیه شود. بنابراین کد زیر نیز غیرقانونی است:
int myNumber;
ShowDouble(ref myNumber);
WriteLine("myNumber = {myNumber}");
تا الآن، از کلمه ی کلیدی ref تنها در پارامترهای تابع استفاده کرده ایم، اما این امکان نیز وجود دارد که آن را در هردوی متغیرهای محلی و return ها مورد استفاده قرار دهیم. در اینجا، myNumberRef به myNumber رجوع می کند و تغییر دادن myNumberRef منجر به یک تغییر در myNumber می شود. اگر مقدار هردوی myNumber و myNumberRef نشان داده شود، این مقدار برای هردوی این متغیرها برابر با 6 خواهد بود:
int myNumber = 5;
ref int myNumberRef = ref myNumber;
myNumberRef = 6;
این امکان نیز وجود دارد که از کلمه ی کلیدی ref بعنوان یک نوع برگشتی استفاده کنیم. به کدهای زیر توجه کنید، که کلمه ی کلیدی ref نوعِ return را به صورت ref int مشخص کرده است و همچنین این کلمه در بدنه ی کد نیز قرار دارد که به این تابع دستور می دهد تا ref val را برگرداند:
static ref int ShowDouble(int val)
{
val *= 2;
return ref val;
}
اگر تلاش کنید تابع بالا را کامپایل کنید، یک خطا دریافت خواهید کرد. علتش این است که ما نمی توانیم یک نوعِ متغیر(یعنی مثلا int) را بعنوان یک پارامتر تابع مرجع(by reference) ، بدون قرار دادن کلمه ی کلیدی ref در اعلان این متغیر پاس دهیم. قطعه کد زیر را مشاهده کنید که در ان کلمه ی کلیدی ref اضافه شده است؛ این تابع کامپایل می شود و همان طور که انتظار می رود، اجرا می شود.
static ref int ShowDouble(ref int val)
{
val *= 2;
return ref val;
}
متغیرهایی مانند رشته ها و آرایه ها، از نوع مرجع( reference types) هستند و آرایه ها می توانند بدون اینکه یک پارامتر تعریف شود با کلمه ی کلیدی ref برگردانده شوند:
static ref int ReturnByRef()
{
int[] array = { 2 };
return ref array[0];
}
نکته: با اینکه رشته ها از نوع مرجع(reference types) هستند، یک مورد خاص محسوب می شوند زیرا تغییر ناپذیر هستند. این یعنی اینکه ما نمی توانیم آنها را تغییر دهیم زیرا یک تغییر در آنها منجر به ایجاد یک رشته ی جدید می شود؛ و رشته ی قدیمی واگذار می شود. اگر سعی کنید رشتهای را با استفاده از ref برگردانید، کامپایلر سی شارپ Roslyn، خطا میدهد.
- بازدید: 83
1. سعی کنید نظرات شما مرتبط با مقاله ی مورد نظر باشد، در غیر این صورت پاسخ داده نخواهد شد.
2. سوالات خود را به صورت کوتاه بیان کنید و از پرسیدن چند سوال به طور همزمان خودداری کنید.
3. سوال خود را به طور واضح بیان کنید و از کلمات مبهم استفاده نکنید.