در كل #C شما با دو نوع داده روبهرو هستید: یكی Value Type یكی هم Reference Type. در شمارههای پیشین بیشتر در مورد این نوع دادهها صحبت كردهایم و در حال حاضر فقط تفاوت آنها را بررسی میكنیم. نوع اول یك نوع بر حسب مقدار است و زمانی كه به یك تابع فرستاده میشود اگر درون تابع تغییری روی آن صورت بگیرد درون خود تابع اعتبار دارد و زمانی كه از تابع خارج شویم مقدار متغیر فرستاده شده به تابع بدون تغییر میماند (دقیقا مانند متغیرهای معمولی در C و ++C)، اما Reference Type چطور؟ همان طور كه از نام آنها بر میآید از نوع ارجاع هستند یعنی وقتی به یك تابع فرستاده شوند هر تغییری در آنها بیرون از تابع نیز اعمال میشود، بگذارید مطلبی را كه گفته شد از دیدگاه زبان C بررسی كنیم.
وقتی نوع اول را به یك تابع میفرستیم در واقع مقدار آن كه یك كپی از آن است، به تابع فرستاده میشود. اما در نوع دوم وقتی به یك تابع فرستاده میشود در واقع یك اشارهگر به متغیر اصلی است كه به تابع اصلی فرستاده میشود، اما نحوه ذخیرهسازی آنهاست كه باعث این تفاوت در ساختار آنها میشود. در نوع اول متغیر كامل در Stack ذخیره میشود و در نوع دوم كل متغیر در حافظه Heap و اشارهگر به آن در Stack به عنوان یك متغیر ذخیره میشود كه به داده كپی شده در Heap اشاره دارد. شما نمیتوانید مقدار اشارهگر را تغییر دهید، بلكه میتوانید محتویات خانهای را كه اشارهگر به آن اشاره میكند تغییر دهید (این كار دلیل امنیتی دارد).
در داتنت كلاسها یك نوع داده ارجاعی هستند یعنی Reference Type و Structure یك نوع داده مقداری یعنی Value Type. String در #C یك كلاس هست پس از نوع Reference Type است. حال مثال زیر را اجرا كنید:
static void Main(string[] args){
int x = 20;
double y = 30;
string name = “Jamejam”;
Test(x, y, name);
Console.WriteLine(x.ToString());
Console.WriteLine(y.ToString());
Console.WriteLine(name);}
public static void Test(int x,double y,string name){
x = 10;
y = 20;
name = “Click!”;}
خروجی که مشاهده میکنید به صورت زیر است
20
30
Jamejam
اما چه اتفاقی افتاده؟ چرا متغیر name مقدار اولیه خود را دارد؟ در صورتی كه مقدار آن در تابع برابر Click! قرار داده شده است.
ما انتظار داریم كه چون string یك كلاس است، پس وقتی به تابع Test داده میشود، مقدار آن تغییر كند. اما چرا تغییر نكرد؟
بله این غیر عادی است؛ اما بر میگردیم به تعریف كلاس string، كلاس string یك كلاس Immutable است.
كلاس Immutable به كلاسی اطلاق میشود كه بعد از ساخته شدن نمیتواند مقدار خود را تغییر دهد. یعنی وقتی شما یك شئ از این كلاس ساختید و مقدار آن را تغییر دادید در واقع یك كپی جدید از آن شئ تحویل میگیرید نه همان شئ تغییر داده شده را. در مثال بالا وقتی شما به متغیر name مقداری را میدهید، اين مقدار تغییر نمیكند، بلكه یك شئ جدید تحویل میدهد كه در همان Scope اعتبار دارد. پس توجه داشته باشید وقتی از string استفاده میكنید، انتظار تغییر آن را نداشته باشید و برای اینكه تغییرات را مشاهده كنید، از كلمات كلیدی ref و out (در شمارههای پیشین توضیح داده شده است) استفاده كنید.
اما كلاس string یك مشكل دیگر نیز دارد. به كد زیر دقت كنید.
string name = “Jamejam”;
name += “Click!”;
Console.WriteLine(name);
همه چیز درست است. اما طبق گفتههای بالا مقدار متغیر name سه رشته را دارد، یكی Jamejam و دیگری Jamejam Click، چون هر بار كه تغییر میكند یك شئ جدید تحویل میدهد؛ پس متغیر name میماند و یك name دیگر تحویل میدهد. پس شما 2 رشته دارید و اگر به كرات از این روش استفاده كنید، شما مقدار زیادی رشته تولید شده دارید كه همیشه از یكی از آنها كه آخری است، استفاده میكنید. این موضوع در زمانهاي زیادی كه برنامه شما كار میكند ممكن است مشكل ايجاد كند و برنامه با كمبود حافظه روبهرو شود. البته این اتفاق برای متغیرهای رشتهای بزرگ میافتد، اما بهتر است از روشهای بهتری استفاده كنیم تا هیچ وقت با مشكل روبهرو نشویم.
برنامهنویسان داتنت برای این مشكل نیز راهحلی دارند آن هم استفاده از كلاس StringBuilder است. این كلاس در فضای نام System.Text قرار دارد. شما توسط متد Append این كلاس میتوانید یك رشته را به یك رشته دیگر تبدیل كنید بدون اینكه مشكلاتی كه در بالا ذكر شده، رخ دهد (اینكه چگونه این كار انجام میشود به عهده خواننده است)، سپس با استفاده از متد ToString مقدار رشته حاصل را بازیابی كنید. به مثال زیر دقت كنید:
StringBuilder sb = new StringBuilder();
sb.Append(“Jamejam”);
sb.Append(“Click!”);
Console.WriteLine(sb.ToString());
امیربهاءالدین سبطالشیخ