رفرنس تایپ‌ها چگونه به ورودی متدها ارسال می‌شوند
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: سه دقیقه

اگر شما یک تایپ از نوع reference type را در ورودی یک متد قرار دهید و در داخل متد، پراپرتی‌های این تایپ را ویرایش کنید، بعد از آنکه از متد خارج می‌شود، تغییرات خود را مشاهده خواهید کرد. به طور مثال کد زیر را در نظر بگیرید که در داخل متد EditUserName، مقدار پراپرتی Name را تغییر داده‌ایم:
public class User
{
    public string Name { get; set; }
}
class Program
{
    static void Main(string[] args)
    {
        User user = new User
        {
            Name = "Farhad"
        };
        EditUserName(user);
        Console.WriteLine(user.Name);
        //Print Zamani in  console 
    }
    public static void EditUserName(User userCopy)
    {
        userCopy.Name = "Zamani";
    }
}
اگر کد بالا را اجرا کنید، مقدار "Zamani" را در صفحه کنسول مشاهده میکنید.
 اگر یک متغیر از نوع Value type مانند int را به ورودی متدی ارسال کنید و آن را در داخل متد تغییر دهید، تغییرات خود را بعد از آنکه از متد خارج میشود، مشاهده نمیکنید.
اما اگر در داخل متد (EditUserName) بالا که کلاس User را پاس داده‌ایم، مقدار پارامتر userCopy را برابر null کنیم چه اتفاقی میافتد؟ (خودم اول فکر کردم بعد از اینکه از متد EditUserName خارج میشه و میخواد user.Name رو چاپ کنه، Null reference exception رخ میده؛ ولی نه).
اگر تغییرات زیر را اعمال کنیم و مجددا برنامه را اجرا کنیم، همان نتیجه‌ی قبلی را مشاهده میکنیم:
static void Main(string[] args)
{
    User user = new User
    {
        Name = "Farhad"
    };
    EditUserName(user);
    Console.WriteLine(user.Name);
    //Print Zamani in console
}
public static void EditUserName(User userCopy)
{
    userCopy.Name = "Zamani";
    userCopy = null;
}
اگرچه نوع userCopy از نوع reference type میباشد، اما بعد از آنکه از متد خارج میشود، مقدار قبلی خود را دارد، چرا؟ 
زیرا زمانیکه شما مقدار user را به متد EditUserName پاس میدهید، یک کپی از آبجکت user به متد ارسال میشود، یعنی یک کپی از متغیر user ایجاد میشود و به ورودی متد ارسال میشود (خود متغیر user ارسال نمیشود) . بر این اساس میتوان گفت که user و userCopy هر دو به یک مکان از حافظه اشاره دارند که userCopy به متد EditUserName ارسال شده است.

 و زمانی که مقدار userCopy را برابر null میکنید، رفرنسی که به آن اشاره دارد، از بین میرود.

به همین دلیل اگر در داخل متد، پارامتری که از نوع reference type است را برابر null کنید و یا new کنید، بعد از آنکه از متد خارج شود، تغییرات را مشاهده نمی‌کنید. همین عمل برای نمونه سازی داخل متد نیز صدق میکند.
 برای مثال در کد زیر در داخل متد EditUserName، پارامتر userCopy را new میکنیم و سپس مقدار نام آن را تغییر میدهیم و بعد از آنکه از متد خارج میشود، همان مقداری را نشان میدهد که قبل از new شدن اعمال شده بود.
static void Main(string[] args)
{
    User user = new User
    {
        Name = "Farhad"
    };
    EditUserName(user);
    Console.WriteLine(user.Name);
    //Print Zamani in console
}
public static void EditUserName(User userCopy)
{
    userCopy.Name = "Zamani";
    userCopy = new User();
    userCopy.Name = "Farhad";
}
اگر کد بالا را اجرا کنید مجددا "Zamani" را در صفحه کنسول مشاهده میکنید؛ زیرا زمانیکه userCopy را new میکنید، رفرنسی که userCopy به آن اشاره دارد، تغییر میکند و به مکانی دیگر از حافظه اشاره میکند و تغییرات بر روی user که در متد Main قرار دارد اعمال نمیشود. 
در متغیر از نوع رفرنس، آدرس آبجکت اصلی کپی می‌شود و در واقع پارامتر، یک متغیر جدید است که آدرس ابجکت اصلی را دارد؛ بنابراین هنگامیکه به اعضای آبجکت دسترسی صورت گیرد، از طریق آدرس، به همان عضو آبجکت اصلی اشاره شده و درنتیجه تغییر، ماندگار می‌ماند. اما هنگامیکه خود پارامتر کلاس مقدار دهی شود، یک فضای جدید در حافظه ایجاد شده و آدرس آن در محتوای پارامتر کپی می‌شود. اینگونه پس از پایان متد، تغییر پایا نبوده، چرا که آدرس پارامتر، با آبجکت اصلی متفاوت خواهد بود. 
  • #
    ‫۳ سال و ۴ ماه قبل، پنجشنبه ۲ اردیبهشت ۱۴۰۰، ساعت ۱۷:۴۷
    اینجا بود که ref  keyword معرفی شد.