اینجا میتونی برنامه نویسی ویندوز رو به طور کاملا رایگان یاد بگیری
2 سال پیش / خواندن دقیقه

داده نوع های Value Type و Reference Type

سه شارپ داده نوع ها را بسته به چگونگی ذخیره مقادیرشان در حافظه به دو دسته تقسیم میکند :

  1. Value Type
  2. Reference Type

Value Type

به داده نوعی Value Type گفته میشود که یک مقدار را در فضای حافظه ی خود ذخیره کند. و این به این معناست که متغیر هایی که از نوع این داده نوع تعریف میشوند به طور مستقیم دارای مقداری در خود هستند.

نکته : تمام Value Type ها از فضای نام System.ValueTypeمشتق میشوند که آن فضای نامی هم در فضای نام System.Object قرار دارد.

 

برای مثال متغیری از نوع int را در نظر بگیرید : 

int i = 100;

سیستم مقدار عدد صحیح ۱۰۰ را در فضای حافظه ای که برای متغیر "i" تخصیص داده شده است ، ذخیره می کند.

تصویر زیر نحوه ی ذخیره سازی مقدار ۱۰۰ را در حافظه به آدرس (۰x۲۳۹۱۱۰) برای متغیر "i" نشان میدهد :

داده نوع های Value Type و Reference Type

همه ی داده نوع هایی که در زیر آورده شده است از نوع value type هستند :

   bool    byte    char    decimal    double
   enum    float    int    long    sbyte
   short    sbyte    unit    ulong    ushort

ارسال با مقدار

وقتی یک متغیر از نوع Value Type را به عنوان آرگومان برای یک متد ارسال می کنید ، سیستم یک کپی جداگانه از آن متغیر را ایجاد کرده و آن را برای متد ارسال میکند. بنابراین اگر تغییری در مقدار آن متغیر در متد مربوطه ایجاد شود تاثیری بر مقدار اصلی آن ندارد.

نمونه مثال زیر نحوه ی عملکرد روش ارسال با مقدار را نشان میدهد :

static void ChangeValue(int x)
{    x =  200;
    Console.WriteLine(x);
}

static void Main(string[] args)
{    int i = 100;
    Console.WriteLine(i);        ChangeValue(i);        Console.WriteLine(i);
}

در نمونه مثال فوق، "i" متغیری است که در متد Main تعریف و مقدار دهی شده است. متغیر "i" را به متدی به نام ()ChangeValue ارسال میکنیم (ارسال با مقدار). با وجود اینکه مقدار این متغیر در متد ()ChangeValue تغییر میکند ولی به خاطر اینکه روش ارسالی ، ارسال با مقدار است یک کپی از متغیر "i" برای متد ارسال شده است و تغییر در آن هیچ تاثیری برای مقدار اولیه ی متغیر "i" ندارد. با چاپ مقدار متغیر "i" در انتهای برنامه  به وضوح میتوان دید هیچ تغییری در مقدار آن ایجاد نشده است :

100 200 100

Reference Type

برخلاف Value Type ها ، Reference Type ها مقادیرشان را به صورت مستقیم در خود ذخیره نمی کنند. در عوض آنها آدرس مکانی از حافظه را که مقدار در آن قرار گرفته است، در خود ذخیره میکنند. به عبارت دیگر Reference Type ها شامل یک اشاره گر هستند که به مکانی دیگر از حافظه اشاره میکند که داده یا مقدار در آن ذخیره شده است.

برای این حالت یک متغیر رشته ای را میتوان مثال برد :

string s = "Hello Worlds";

تصویر زیر چگونگی تخصیص حافظه را برای متغیر رشته ای بالا نشان میدهد :


داده نوع های Value Type و Reference Type
همانطور که در تصویر بالا مشاهده می کنید سیستم یک مکان تصادفی در حافظه (۰x۸۰۳۲۰۰) را برای متغیر "S" انتخاب کرده است. مقداری که در متغیر "S" قرار میگیرد ۰x۶۰۰۰۰۰ است که آدرس خانه ای از حافظه است که مقدار اصلی یعنی !!Hello Worlds در آن قرار گرفته است.

داده نوع های زیر همگی Reference Type هستند :

  • String
  • تمام آرایه ، حتی اگر مقادیر آنها از نوع value type باشد
  • Class
  • Delegates

ارسال با ارجاع

وقتی یک متغیر Reference Type را به عنوان آرگومان از یک متد به متد دیگری میفرستید دیگر کپی ایی از آن ساخته نمیشود. در عوض آدرس آن متغیر به متد مربطه ارسال میشود. نمونه مثال زیر روش ارسال با ارجاع را نشان میدهد :

static void ChangeReferenceType(Student std2)
{    std2.StudentName = "Steve";
}

static void Main(string[] args)
{    Student std1 = new Student();    std1.StudentName = "Bill";        ChangeReferenceType(std1);
    Console.WriteLine(std1.StudentName);
}

در نمونه مثال فوق ، از آنجایی که Student یک کلاس (class) است هنگامی که شی ایی از کلاس Student به نام std۱ را به عنوان آرگومان به متد ()ChangeReferenceType ارسال می کنیم ، آن چیزی که در عمل ارسال میشود آدرس حافظه ی شی std۱ است. بنابراین وقتی متد ()ChangeReferenceType فیلد StudentName را تغییر میدهد ، مقدار اصلی فیلد StudentName از شی std۱ را تغییر میدهد. به همین دلیل شی std۱ و آرگومان std۲ هر دو به یک آدرس در حافظه اشاره میکنند. بنابراین این خروجی برابر با رشته ی steve است :

Steve

مقدار null

Reference Type ها موقعی که هنوز مقداردهی نشده اند به صورت پیشفرض دارای مقدار null هستند. برای مثال یک متغیر رشته ای (و یا هر متغیر از نوع Reference Type) اگر مقدار دهی نشوند دارای مقدار null هستند و عملا به هیچ جایی اشاره نمی کنند . تصویر زیر مقدار null برای شی ایی که مقدار دهی نشده است را  نشان میدهد :


داده نوع های Value Type و Reference Type
یک متغیر از نوع  Value Type نمیتواند null باشد به این دلیل که آنها یک مقدار را میپذیرند نه یک آدرس را . با این حال متغیر های Value Type قبل از اینکه استفاده شوند باید مقدار دهی شوند. در صورتی که سعی کنید از یک متغیر محلی از نوع Value Type بدون اینکه آن را مقدار دهی کنید استفاده کنید با خطای زمان کامپایل مواجه میشوید :

void someFunction()
{    int i;
    Console.WriteLine(i);
}

با این حال فیلد های Value Type در یک کلاس میتوانند بدون مقدار دهی اولیه تعریف شوند و در این صورت آنها دارای مقدار پیشفرض هستند برای مثال مقدار پیشفرض برای داده نوع int مقدار ۰ و مقداریفرض برای فیلدی که از نوع بولین (bool) تعریف شده باشد false است.

using System;
 
public class myClass{
     public int i;
    
}

public class Program
{
         public static void Main()
    {
        myClass mcls = new myClass();
         Console.WriteLine(mcls.i);
    }
}

نکته : از زمان معرفی #C نسخه ۲ به بعد نوع های nullable (انواعی که null را هم می پذیرند) معرفی شدند بنابراین شما میتوانید مقدار null را به متغیر ها انتساب دهید (در این حالت باید از قاعده ی نوشتاری متفاوتی در تعریف یک متغیر استفاده کرد)

نکات زیر را بیاد داشته باشید :

  • Value Type ها مقادیر را در فضای حافظه ی خود ذخیره میکنند در حالی که Reference Type  ها آدرس یک مقدار را در فضای خود ذخیره میکنند.
  • داده نوع های اولیه و داده نوع struct از نوع Value Type هستند.اشیای class ها ، string ، array و delegate از نوع Reference Type هستند.
  • Value Type ها به صورت پیفرض با مقدار ارسال میشوند در حالی که Reference Type ها با ارجاع ارسال میشوند.
  • Reference Type ها و Value Type ها بسته به حوزه و مکان قرار گیری آنها در Stack و  Heap ذخیره میشوند.
شاید از نوشته‌های زیر خوشتان بیاید
نظر خود را درباره این پست بنویسید ...

منوی سریع