Регистрация Главная Сообщество
Сообщения за день Справка Регистрация
Навигация
Zhyk.org LIVE! Реклама на Zhyk.org Правила Форума Награды и достижения Доска "почета"

Ответ
 
Опции темы
Старый 30.07.2013, 03:08   #1
 Старший сержант
Аватар для Sinyss
 
Sinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака Норриса
Регистрация: 29.07.2011
Сообщений: 197
Популярность: 8989
Сказал(а) спасибо: 45
Поблагодарили 175 раз(а) в 139 сообщениях
Отправить сообщение для Sinyss с помощью Skype™
 
По умолчанию Различия между ref и value type переменными.

В своей прошлой статье я обещал уделить внимание различиям между значимым(value) и ссылочным(reference) типом переменных.
С# предоставляет 2 типа - класс и структура, которые почти идентичны, но 1й ссылочного, а 2й значимого типа.
Что такое структура?
Если по-простому то это обрезанный класс. Если из класса убрать поддержку наследования, методов сборки мусора то вы получите структуру. Структуры определяются так же как и классы, только используется ключевое слово struct вместо class. Структуры так же обладают теми же членами что и классы, конструкторы, поля, методы, свойства, операторы. Простой пример структуры:
Код:
struct Point
{
   private int x, y;             // приватные поля
 
   public Point (int x, int y)   // конструктор
   {
         this.x = x;
         this.y = y;
   }

   public int X                  // свойство
   {
         get {return x;}
         set {x = value;}
   }

   public int Y
   {
         get {return y;}
         set {y = value;}
   }
}
Значимые и ссылочные типы:
Есть еще 1 различие между структурой и классом и оно самое важное для понимания. В рантайме(во время исполнения программы) виртуальная машина обращается с значимыми и ссылочными типами по разному. Когда создается структура, в памяти выделяется 1 место для хранения ее значения (То же касается примитивных типов, таких как int, float, bool, char). Когда рантайму надо значение переменной он напрямую обращается к значению, что может быть очень эффективно, в частности с примитивными типами.
Со ссылочными типами все иначе, объект создается в памяти а потом управляется через отдельную ссылку, которая скорее указатель. Допустим Point это структура, а Form это класс. Создание экземпляра происходит так:
Код:
Point p1 = new Point();         // Структура
Form f1 = new Form();           // Класс
В первом случае 1 место выделяется для хранения значения p1. А во втором случае выделяется 2 места , 1 для объекта, а второе для его ссылки. Будет понятней если переписать 2ю строку так:
Код:
Form f1;                        // Размещаем ссылку на обьект (null)
f1 = new Form();                // Размещаем значение обьекта
Если мы скопируем объекты в новые переменные:
Код:
Point p2 = p1;
Form f2 = f1;
p2, будучи структурой становится независимой копией p1, со своими, отдельными полями.
Но в случае с f2, все что мы скопировали это ссылка, и f1 и f2 указывают на 1 и тот же объект.

ВАЖНОЕ
При передаче как параметр в метод:
В C# по умолчанию параметры передаются по значению, что означает что они будут скопированы и потом переданы методу. Для значимых типов это означает физическое копирование экземпляра(как p2 было скопировано), в то время как для ссылочных типов это означает копирование только ссылки. Пример:
Код:
Point myPoint = new Point (0, 0);      // новая value-type переменная
Form myForm = new Form();              // новая reference-type переменная
Test (myPoint, myForm);                // Метод для теста
 
void Test (Point p, Form f)
{
      p.X = 100;                       // Без еффекта на MyPoint поскольку p - копия
      f.Text = "Hello, World!";        // Это изменит текст в myForm поскольку
                                       // myForm и f указывают на 1 объект
      f = null;                        // без эффекта на myForm
}
Присвоение f значения null ничего не изменит, поскольку это копия ссылки, и мы стерли только копию.
Мы можем изменить то как передаются параметры с помощью ключевого слова ref. Когда мы передаем "по ссылке", метод обращается напрямую к аргументам с которыми метод был вызван. В примере ниже вы можете представить что f и p были замещены myPoint и myForm
Код:
Point myPoint = new Point (0, 0);      // новая value-type переменная
Form myForm = new Form();              // новая reference-type переменная
Test (ref myPoint, ref myForm);        // передаем myPoint и myForm по ссылке

void Test (ref Point p, ref Form f)
{
      p.X = 100;                       // Это изменит позицию myPoint (ну или значение свойства X если точнее).
      f.Text = “Hello, World!”;        // Это изменит текст в myForm
      f = null;                        // Это уничтожит переменную  myForm
}
В этом случае присвоение null к f также сделает myForm null, потому что в этот раз мы работаем с оригинальной ссылкой на переменную а не с ее копией.

Расположение в памяти:
CLR выделяет память для объектов в двух местах: в стеке и в куче. Стек - простая структура которая работает по принципу первый зашел - последний вышел (first-in-last-out) FILO. Когда вызывается метод CLR сохраняет ссылку на верхушку стека. Метод запихивает(push) данные в стек по мере выполнения. Когда метод завершается, CLR "выпихивает"(pop) данные сохраненные методом в стеке пока не найдет сохраненную ссылку.
Куча в то же время может быть представлена как случайно перемешанная куча объектов. Ее преимущество в том что она позволяет объектам размещаться и убираться из кучи в любом порядке. Куча требует траты ресурсов на менеджер памяти(дефрагментация объектов) и сборщик мусора(определяет, есть ли в стеке ссылка на объект, если нету - удаляет объект.) что бы держать кучу в порядке.
Для демонстрации работы стека и кучи рассмотрим пример:
Код:
void CreateNewTextBox()
{
      TextBox myTextBox = new TextBox();             // TextBox - класс
}
В этом методе мы создаем локальную переменную которая указывает на объект(короче - адрес). Локальная переменная хранится в стеке, в то время как сам объект хранится в куче.
Стек всегда используется для хранения 2х вещей:
1) Ссылочной части локальных переменных ссылочного типа и параметров (таких как ссылка на myTextBox).
2) Локальных переменных ссылочного типа и параметров метода (структуры, простые типы)
В куче хранятся:
1) Содержимое объектов ссылочного типа.
2) Любая структура внутри объекта ссылочного типа. (Например если в классе есть структура то она будет хранится в куче а не в стеке.)

Очистка памяти
После того как мы выполнили CreateNewTextBox() локальная переменная myTextBox, которая хранится в стеке будет выпихнута из стека. Но что произойдет с объектом на который она ссылалась? Мы можем игнорировать его, сборщик мусора отловит его позже(когда именно - не известно) и автоматически удалит из кучи.
Сборщик знает что надо удалить его, потому что, на него не ссылаются из стека или нету такой цепочки ссылок которая бы привела к этому объекту. Программисты C++ которые заботятся об утечках памяти захотят его удалить, но вообще то невозможно удалить конкретный объект программно. Мы должны полагаться на очистку памяти средствами CLR.
НО! У автоматической сборки мусора есть фича. Объекты которые работают с другими ресурсами(кроме памяти) (в частности "handles", такие как Windows handles, file handles, SQL handles) должны быть закрыты уже программно(то есть приказать прекратить использовать ресурс. например File.Close()) когда в этих ресурсах уже нету нужды. Тоже касается всех компонентов Windows, поскольку у них есть Windows handles. Вы можете спросить, почему нельзя утилизировать такие ресурсы в финалайзерах объекта(финалайзер - метод который увеличивает приоритет объекта быть утилизированным сборщиком мусора). Основная причина в том что сборщик мусора больше заботится о памяти а не о ресурсах. Так что на ПК где есть пару гигабайт свободной оперативной памяти, сборщик мусора может ждать один-два часика прежде чем запустится. (из логики что оперативная память все равно не надо операционной системе).
Вернемся к нашему TextBox, пример был немного искусственный, поскольку что бы компонент отобразился надо было бы его добавить в Controls какого то элемента. Дополнительный бонус от такого размещения в том что когда этот элемент будет закрыт то для каждого его элемента в Controls будет автоматически вызван метод Dispose, который "отпускает" Windows handle и убирает его с экрана.
Немного деталей
Тоже самое касается классов типа FileStream их тоже надо "уничтожать" вручную. К счастью C# предоставляет спец. конструкцию using для уничтожения таких объектов:
Код:
using (Stream s = File.Create ("myfile.txt"))
{
   ...
}
Данный код можно перевести в следующий:
Код:
Stream s = File.Create ("myfile.txt");
try
{
   ...
}
finally
{
   if (s != null) s.Dispose();
}
Блок finally позаботится что метод Dispose будет вызван если произойдет исключение.

Немного о сборке мусора в WPF

Спасибо за внимание.
PS: Если нашли ошибку - отпишите в личку, в 2 ночи дописывал статью, мог что то пропустить.
  Ответить с цитированием
6 пользователя(ей) сказали cпасибо:
Буянь (01.08.2013), крайслер (03.08.2013), Nickitee (31.07.2013), object (06.08.2013), warl0ck (30.07.2013), Yukikaze (02.08.2013)
Старый 02.08.2013, 15:59   #2
 Разведчик
Аватар для Буянь
 
Буянь блестящий пример для подражанияБуянь блестящий пример для подражанияБуянь блестящий пример для подражанияБуянь блестящий пример для подражанияБуянь блестящий пример для подражанияБуянь блестящий пример для подражанияБуянь блестящий пример для подражанияБуянь блестящий пример для подражанияБуянь блестящий пример для подражанияБуянь блестящий пример для подражанияБуянь блестящий пример для подражания
Регистрация: 05.03.2011
Сообщений: 20
Популярность: 1883
Сказал(а) спасибо: 13
Поблагодарили 44 раз(а) в 36 сообщениях
Отправить сообщение для Буянь с помощью Skype™
 
По умолчанию Re: Различия между ref и value type переменными.

Долго втыкал по поводу ref'ов. И подумал, а так не будет нагляднее?
Типа код.

Типа результат, картинкой
  Ответить с цитированием
Пользователь сказал cпасибо:
Sinyss (02.08.2013)
Старый 02.08.2013, 16:16   #3
 Старший сержант
Аватар для Sinyss
 
Sinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака НоррисаSinyss троюродный дядя Чака Норриса
Регистрация: 29.07.2011
Сообщений: 197
Популярность: 8989
Сказал(а) спасибо: 45
Поблагодарили 175 раз(а) в 139 сообщениях
Отправить сообщение для Sinyss с помощью Skype™
 
По умолчанию Re: Различия между ref и value type переменными.

Так читателю придется компилить код, что бы понять, в моем случае достаточно читать...
PS: Вообще выходит довольно много информации в 1й статье, тяжело за раз воспринимать, надо чем то разбавлять...
  Ответить с цитированием
Ответ


Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
[Помогите!] Расчет расстояния между векторами Annedroid Общение разработчиков 6 05.09.2012 23:15
[Информация] Переговоры между расами ~ВаняБелый~ Статьи и руководства по Aion 13 12.10.2011 19:37
Работа с переменными moloko911 С/С++ 1 09.09.2011 23:25
[Баг] Точка назначение между A и B Max Payne 2010 Статьи и руководства по Aion 2 25.06.2011 15:45
В чём различия между вх реесторным и инжекторным? Niset Общение и обсуждение, архив Point Blank 21 09.03.2011 21:37

Заявление об ответственности / Список мошенников

Часовой пояс GMT +4, время: 22:48.

Пишите нам: [email protected]
Copyright © 2024 vBulletin Solutions, Inc.
Translate: zCarot. Webdesign by DevArt (Fox)
G-gaMe! Team production | Since 2008
Hosted by GShost.net