ش | ی | د | س | چ | پ | ج |
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
در سی شارپ 2 نوع داده اصلی وجود دارد ؛ یکی Value-Type و دیگری Reference-Type . اولی بر حسب مقدار است، یعنی همیشه مقدار آن اهمیت دارد و در صورت پاس دادن آن به توابع دیگر و تغییر مقدار آن، تغییر در حوزه همان تابع باقی و مقدار اصلی آن همیشه ثابت میماند. در Reference-Type ارجاع متغیر مهم است و اگر مقدار آن در هر جایی تغییرکند در متغیر اصلی نیز تغییر داده میشود، به این دلیل که همیشه اشارهگر آن به یک تابع داده میشود.
تبدیل بین نوع دادهها یکی از عملیات مرسوم است که در سی شارپ با 2 اصطلاح شناخته میشود؛ Boxing و UnBoxing در حالت اول تبدیل بین دادههایی از نوع Value-Type به Reference-Type صورت میگیرد و در حالت دوم تبدیل بین Value-Type به Reference-Type انجام میشود.
با یک مثال این موضوع را توضیح میدهیم.
یک ساختار داده به صورت زیر داریم:
struct Point{
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;}}
این ساختار شامل یک سازنده و دو ویژگی عمومی به نامهای x و y است. حالا به کد زیر دقت کنید:
Point p = new Point(10,20);
Object box = p;
p.x = 20;
Console.WriteLine(((Point)box).x);
خروجی ای که انتظار داریم نمایش داده شود عدد ۲۰ است، اما در خروجی ۱۰ ظاهر میشود، چرا؟
دلیل آن خیلی ساده است، Point یک struct است و یک نوع داده Value-Typeمحسوب می شود و زمانی که آن را به یک نوع داده Reference-Type تبدیل میکنید، یک کپی از خود تولید کرده که مجزا از مقدار اصلی است؛ به این عمل اصطلاحا Boxing گفته میشود.
عمل Unboxing تبدیل از نوع داده Reference-Type به نوع داده Value-Type است، به خروجی زیر دقت کنید:
Point p = new Point(10, 20);
object box = p;
Point p1 = ((Point)box);
Box = new Point(50,40);
Console.WriteLine(p1.x);
ما انتظار خروجی ۵۰ را داریم اما خروجی ۲۰ را به ما میدهد، چرا؟
به این دلیل که box یک متغیر از نوع ارجاع بوده و وقتی آن را به یک Point که یک متغیر از نوع مقدار است تبدیل میکنید، یک کپی را در p1 ایجاد میکند. از آنجا که p1 از نوع مقدار است هر تغییری در box در p1 دیده نمیشود.
حال ببینیم در پشت این تبدیلها چه اتفاقاتی رخ میدهد.
عمل Boxing یک مقدار Value-Type را به یک مقدار Reference-Type تبدیل میکند. در این تبدیل متغیر Value-Type در حافظه Stack قرار دارد و اشارهگر متغیر Reference-Type که قرار است به آن تبدیل شود نیز در Stack است، بعد از تبدیل کامپایلر یک کپی از متغیر اولی ایجاد میکند و آن را در جایی از حافظه Heap قرار میدهد که اشارهگر متغیر دوم به آنجا اشاره میکند. در نتیجه هر تغییری در متغیر اول در متغیر دوم اثری نخواهد گذاشت.
اما در عمل Unboixing چه اتفاقی میافتد؟ در این حالت متغیر Reference-Type که در حافظه ایجاد شدهاست، یک متغیر از نوع داده مقصد در Stack ایجاد میکند سپس یک کپی از محتویات خانهای که به آن اشاره دارد در آن ایجاد میکند، اما یک نکته در این تبدیل وجود دارد، زمانی این عمل بدرستی انجام میشود که نوع داده Reference-Type از عمل Boxing به وجود آمده باشد؛ مثل کد زیر:
Object obj = 123
Int j = (int)obj;
نکته دیگر در تبدیلها این است که در حالت Unboxing نوع داده مقصد باید بصراحت ذکر شود (در مثال بالا int قبل از obj این را نشان میدهد)، اما در حالت Boxing به صورت ضمنی تبدیل صورت میگیرد. در شمارههای بعدی در مورد تبدیلهای ضمنی و آنهایی که به وضوح اعلام میشود، توضیحاتی خواهیم داد.
امیربهاءالدین سبطالشیخ