نوع داده (Data type)
در دنیای واقعی، برای نگهداری مواد مختلف، ظروف مختلفی با اندازه های مختلف طراحی شده است. در دنیای برنامه نویسی نیز با توجه به اطلاعاتی که می خواهیم در حافظه ذخیره کنیم باید نوع ظرف مناسب خود را انتخاب کنیم. نوع ظرف ذخیره سازی در دنیای برنامه نویسی توسط نوع داده ها (Data Type) مشخص می شود. زبان سی شارپ یک زبان Strongly Typed است. به این معنی که تمامی نوع های داده در آن مشخص می باشند. تمامی نوع های داده در سی شارپ به دو دسته تقسیم می شوند:
- Value Types
- Reference Types
تفاوت این دو نوع داده در نحوه تخصیص حافظه و مدیریت آن ها می باشد. در بستر NET. زمانی که شما متغیری را تعریف و مقداردهی می کنید بسته به نوع داده این متغیرها می توانند در دو حافظه زیر ذخیره شوند:
- Memory Stack
- Memory Heap
این دو حافظه یعنی Stack Memory و Heap Memory از نظر میزان سرعت دسترسی و مدیریت آن ها توسط زبان سی شارپ با یکدیگر تفاوت دارند که در ادامه با این حافظه ها بیشتر آشنا می شویم.
انواع مقداری (Value Types) در سی شارپ
متغیرهایی که از نوع Value Type هستند، مستقیما درون حافظه stack ذخیره می شوند. در NET. انواع داده زیر از نوع Value Type هستند:
زمانی که شما متغیری از نوع value type را تعریف می کنید تا مادامیکه مقداری به آن اختصاص نداده اید، کامپایلر فضایی را برای آن در حافظه Stack درنظر نمی گیرد. به محض اینکه شما مقداری را به متغیری از نوع value type اختصاص می دهید کامپایلر فضایی را برای آن متغییر در حافظه Satck درنظر می گیرد و مقدار متغیر را در فضای درنظر گرفته شده قرار می دهد. حافظه Stack مانند دسته ای از بشقاب هست که روی همدیگر قرار گرفته اند. هر زمان که بخواهید بشقابی را روی دسته بشقاب ها قرار دهید (Push) می بایست آن بشقاب را در بالای دسته قرار دهید. به همین ترتیب هر زمان که بخواهید بشقابی را از این دسته بردارید (Pop) همیشه بشقاب بالایی را برمی دارید. حافظه stack شبیه همین چیدمان است. اولین نفری که وارد حافظه Stack شده، آخرین نفری است که خارج می شود و آخرین ورودی در حافظه stack اولین خروجی از حافظه می باشد. به این روش اصطلاحاً First In Last Out یا FILO می گویند.
اشاره گر پشته در بالاترین بخش حافظه stack قرار می گیرد. زمانی که تابعی فراخوانی می شود این تابع به همراه تمامی متغیرهای Local خودش در داخل حافظه stack قرار می گیرد و با فراخوانی یک تابع جدید تابع جاری بر روی تابع قبلی قرار می گیرد و این روال به همین صورت درباره توابع جدید دیگر ادامه پیدا می کند. مزیت استفاده از حافظه stack در ذخیره سازی متغیرها است، زیرا حافظه به صورت خودکار برای شما مدیریت می شود. شما نیازی به اختصاص دادن حافظه به صورت دستی یا آزاد سازی حافظه ندارید و همه این کارها به صورت خودکار انجام می شود. از آنجا که حافظه stack توسط پردازنده مرکزی بهینه و سازماندهی می شود، بنابراین سرعت خواندن و نوشتن حافظه stack بسیار سریع است. یکی از مهمترین کاربردهای حافظه stack مدیریت متدهای فراخوانی شده داخل برنامه های سی شارپ است. در تصویر زیر شما می توانید نحوه کار حافظه Stack را ببینید.
نکته: تمام value type ها از فضای نام System.ValueType مشتق می شوند که این فضای نام نیز خود در فضای نام System.Object قرار دارد.
برای مثال متغییری از نوع int را درنظر بگیرید:
;int x= 123
با اجرای این دستور کامپایلر فضایی را برای متغیر x در حافظه stack اختصاص می دهد و مقدار 123 را در آن فضا قرار می دهد. تصویر زیر نحوه ذخیره مقدار 123 را در حافظه stack به آدرس 0x004312 برای متغیر x نشان می دهد.
انواع ارجاعی (Reference Types) در سی شارپ
نحوه ذخیره سازی متغیرهایی از نوع Reference Type با نحوه ذخیره سازی متغیرهایی از نوع Value Type تفاوت دارد. برخلاف Value Type ها، Reference Type ها مقادیرشان را به صورت مستقیم در خود ذخیره نمی کنند. Reference Type ها علاوه بر حافظه stack با یک حافظه دیگر به نام Heap نیز سر و کار دارند. حافظه Heap حجم بیشتری نسبت به حافظه Stack در اختیار شما قرار می دهد و از طرفی سرعت دسترسی به آن از حافظه stack کمتر است. حافظه Heap بخشی از حافظه کامپیوتر شما است که به صورت خودکار برای شما مدیریت نمی شود و شما باید خودتان حافظه را مدیریت کنید و مسئولیت آزاد سازی حافظه های اختصاص داده شده به متغیرها را بر عهده بگیرید. زمانی که شما یک متغیر از نوع Reference type تعریف می کنید در ابتدا خانه ای از حافظه stack برای آن متغیر درنظر گرفته می شود. سپس زمانی که شما مقداری را به آن متغیر اختصاص می دهید، مقدار مورد نظر در مکانی از حافظه Heap ذخیره شده و آدرس این خانه از حافظه را داخل متغیر ایجاد شده در حافظه stack قرار می دهد.
دستور زیر را در نظر بگیرید:
;"String name = “Mohammad Ramshini
تصویر زیر چگونگی تخصیص حافظه را برای متغیر رشته ای بالا نشان می دهد :
در سی شارپ نوع داده string ،Object، آرایه ها و انواع تعریف شده توسط کاربر مانند Class، Interface و Delegate از نوع Reference Type هستند.
در زبان سی شارپ شما هر کلاسی که تعریف می کنید از نوع Reference Type است. همانطور که می دانید قبل از استفاده از یک کلاس شما ابتدا باید یک شیء از آن کلاس بسازید. فرض کنید که کلاسی با نام Person تعریف کرده ایم و اکنون می خواهیم نمونه ای از آن را ایجاد کنیم:
;()Person p1= new Person
ایجاد شیء از دو بخش تشکیل شده است:
- تعریف متغیری از نوع کلاسی که میخواهیم شیء ای از روی آن بسازیم.
- ایجاد شیء ای از کلاس مربوطه و قرار دادن آن داخل متغیر
زمانی که شما متغیری برای ساخت شیء ای از روی کلاس تعریف می کنید، در حقیقت مکانی از حافظه Satck را برای آن متغیر درنظر می گیرید.
;Person p1
در مرحله بعد وقتی شما شئ را ایجاد کرده و داخل متغیر قرار می دهید، NET. شئ ایجاد شده را داخل حافظه Heap قرار می دهد و آدرس مربوط به شئ در حافظه Heap را داخل متغیر ایجاد شده در حافظه stack قرار می دهد.
;()Person p1= new Person