اندازهی قلم متن
تخمین مدت زمان مطالعهی مطلب:
سه دقیقه
اگر شما یک تایپ از نوع reference type را در ورودی یک متد قرار دهید و در داخل متد، پراپرتیهای این تایپ را ویرایش کنید، بعد از آنکه از متد خارج میشود، تغییرات خود را مشاهده خواهید کرد. به طور مثال کد زیر را در نظر بگیرید که در داخل متد EditUserName، مقدار پراپرتی Name را تغییر دادهایم:
اگر کد بالا را اجرا کنید، مقدار "Zamani" را در صفحه کنسول مشاهده میکنید.
اگرچه نوع userCopy از نوع reference type میباشد، اما بعد از آنکه از متد خارج میشود، مقدار قبلی خود را دارد، چرا؟
اگر کد بالا را اجرا کنید مجددا "Zamani" را در صفحه کنسول مشاهده میکنید؛ زیرا زمانیکه userCopy را new میکنید، رفرنسی که userCopy به آن اشاره دارد، تغییر میکند و به مکانی دیگر از حافظه اشاره میکند و تغییرات بر روی user که در متد Main قرار دارد اعمال نمیشود.
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"; } }
اگر یک متغیر از نوع 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; }
زیرا زمانیکه شما مقدار 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"; }
در متغیر از نوع رفرنس، آدرس آبجکت اصلی کپی میشود و در واقع پارامتر، یک متغیر جدید است که آدرس ابجکت اصلی را دارد؛ بنابراین هنگامیکه به اعضای آبجکت دسترسی صورت گیرد، از طریق آدرس، به همان عضو آبجکت اصلی اشاره شده و درنتیجه تغییر، ماندگار میماند. اما هنگامیکه خود پارامتر کلاس مقدار دهی شود، یک فضای جدید در حافظه ایجاد شده و آدرس آن در محتوای پارامتر کپی میشود. اینگونه پس از پایان متد، تغییر پایا نبوده، چرا که آدرس پارامتر، با آبجکت اصلی متفاوت خواهد بود.