Дълбоко гмуркане: Стойности и референтни видове в .Net

Типовете в Microsoft .Net могат да бъдат или тип стойност, или референтен тип. Докато типовете стойности обикновено се съхраняват в стека, референтните типове се съхраняват в управляваната купчина.

Тип стойност произлиза от System.ValueType и съдържа данните в собственото разпределение на паметта. С други думи, променливите или обектите или типовете стойности имат свое собствено копие на данните.

Междувременно референтен тип разширява System.Object и сочи към място в паметта, което съдържа действителните данни. Можете да си представите референтен тип, подобен на указател, който имплицитно се пренасочва, когато имате достъп до тях. Вградените референтни типове, поддържани от C #, включват: обект, низ и динамика. Всички основни типове данни, булеви, дата, структури и изброявания са примери за типове стойности. Примерите за референтни типове включват: низове, масиви, обекти на класове и др. За да създадете референтни типове в C #, можете да се възползвате от тези ключови думи: клас, интерфейс и делегат.

Имайте предвид, че за разлика от референтен тип, не можете да извлечете от тип стойност, нито можете да присвоите нулева стойност директно на тип стойност. Можете да присвоите нулева стойност на тип стойност само като се възползвате от нулируеми типове - функция, добавена към по-новите версии на .Net Framework. Когато тип стойност се копира в друг, стойността се копира. Следователно, можете да манипулирате стойностите в тях, независимо от другата - промяна в едната не засяга другата. Напротив, когато копирате тип препратка в друг, препратката се копира. Ако промените единия от тях, другият също е засегнат. Като пример, ако една от препратките е зададена за нула, другата също става нула.

Места за съхранение

CLR съхранява обекти в три типа места за съхранение - регистрите, стека или управляваната купчина. Докато краткотрайните обекти се съхраняват в регистрите или стека, дълготрайните обекти се съхраняват в купчината. Както споменах по-рано, типовете стойности обикновено се съхраняват в стека.

Често срещано заблуждение е, че типовете стойности винаги се съхраняват в стека. По-скоро бих казал, че типовете стойности могат да се съхраняват в стека, когато променливата е или временна променлива, или е локална променлива и JIT компилаторът решава да не регистрира стойността. По същество действителното местоположение на тип стойност зависи от изпълнението на JIT компилатора. Обърнете внимание, че тип стойност може да се съхранява в рамка на стека, в регистъра на процесора или дори в паметта на купчината, ако типът стойност се съдържа вътре в обект, т.е. ако е част от референтен тип. Напротив, референтните типове се съхраняват в GC купчината. Препратката се съхранява в стек, докато обектът се разпределя в купчината.

Екземпляри или препратки от тип стойност се съхраняват в стека, регистъра или в купчината в зависимост от това дали времето на екземпляра или препратката е краткотрайно или дълготрайно. Типът стойност може да се намира в стека, ако те са локални променливи, а в управляваната купчина, ако са полета от клас, т.е. принадлежат или са част от референтен тип.

Преминаване по стойност и преминаване по препратка

Следният списък с кодове илюстрира как можете да предадете променлива на метод по стойност.

 static void Increment(int i)

        {

            i = i + 1;

        }

        static void Main()

        {

            int x = 1;

            Increment(x);

            Console.WriteLine("The value of x is: " +x);

            Console.Read();

        }

Имайте предвид, че можете да предадете тип стойност като препратка към метод, като използвате ключовата дума ref. Следният списък с кодове илюстрира това.

static void Increment(ref int i)

        {

            i = i + 1;

        }

        static void Main()

        {

            int x = 1;

            Increment(ref x);

            Console.WriteLine("The value of x is: " +x);

            Console.Read();

        }

Когато горният код бъде изпълнен, в конзолата ще се покаже съобщението "Стойността на x е: 2".

Бокс и разопаковане

Преобразуването на тип стойност в референтен тип е известно като бокс. Разпаковането е точно обратното - то се определя като процес на преобразуване на референтен тип в тип стойност. Следният кодов фрагмент илюстрира боксиране и разопаковане в C #.

int i = 100;

Object obj = i; //Boxing

i = (int) obj; //Unboxing