C#   Уроки программирования с нуля. Си-шарп для чайников   C#

Здравствуйте, гость!
Вход
Регистрация


Ссылочные типы и типы значений в Си-шарп. Ключевые слова ref и out
В языке Си-шарп все типы данных делятся на две категории – ссылочные типы, и типы значений. Они отличаются способом хранения в памяти, производительностью и другим. В этом уроке мы поговорим, что это всё означает, а также о передаче параметров в метод по ссылке (ключевые слова ref и out).

Типы значений

Эту категорию также называют структурными типами. Типы значений хранятся в стеке. Стек - это область памяти, которая используется для передачи параметров в методы и хранения определенных в пределах методов локальных переменных. Данные переменной типа значения хранятся в самой переменной.

К типам значений относятся:

- Целочисленные типы (byte, sbyte, char, short, ushort, int, uint, long, ulong);
- Типы с плавающей запятой (float, double);
- Тип decimal;
- Тип bool;
- Пользовательские структуры (struct);
- Перечисления (enum).

Код ниже показывает, что при присвоении значения одной переменной значимого типа другой, дальнейшее изменение одной из переменных не влияет на другую. Так потому, что хранение данных значимого типа происходит в самой переменной:

static void Main(string[] args)
{
   int a = 1;
   int b = 2;
   b = a;
   a = 3;
   Console.WriteLine(a); // 3
   Console.WriteLine(b); // 1
}

Ссылочные типы

Переменная ссылочного типа содержит не данные, а ссылку на них. Сами данные в этом случае уже хранятся в куче. Куча - это область памяти, в которой размещаются управляемые объекты, и работает сборщик мусора. Сборщик мусора освобождает все ресурсы и объекты, которые уже не нужны.

К ссылочным типам относятся:

- Классы (class);
- Интерфейсы (interface);
- Делегаты (delegate);
- Тип object;
- Тип string.

В коде ниже был создан простой класс, в котором есть одно поле типа int. Дальше была проделана такая же процедура, как и в случае выше, только результат уже другой. После присвоения одного объекта другому, они стали указывать на одну и ту же область памяти (меняем b – меняется и a):

class Test
{
   public int x;
}
class Program
{
   static void Main(string[] args)
   {
     Test a = new Test();
     Test b = new Test();
     a.x = 1;
     b.x = 2;
     b = a; // присвоение ссылки
     b.x = 3;
     Console.WriteLine(a.x); // 3
     Console.WriteLine(b.x); // 3
}
}

Передача параметров в метод по ссылке. Операторы ref и out

В C# значения переменных по-умолчанию передаются по значению (в метод передается локальная копия параметра, который используется при вызове). Это означает, что мы не можем внутри метода изменить параметр из вне:

public static void ChangeValue(object a)
{
   a = 2;
}

static void Main(string[] args)
{
   int a = 1;
   ChangeValue(a);
   Console.WriteLine(a); // 1
   Console.ReadLine();
}

Чтобы передавать параметры по ссылке, и иметь возможность влиять на внешнюю переменную, используются ключевые слова ref и out.

Ключевое слово ref

Чтобы использовать ref, это ключевое слово стоит указать перед типом параметра в методе, и перед параметром при вызове метода:

public static void ChangeValue(ref int a)
{
   a = 2;
}
static void Main(string[] args)
{
   int a = 1;
   ChangeValue(ref a);
   Console.WriteLine(a); // 2
   Console.ReadLine();
}

В этом примере мы изменили значение внешней переменной внутри метода.

Особенностью ref является то, что переменная, которую мы передаем в метод, обязательно должна быть проинициализирована значением, иначе компилятор выдаст ошибку «Use of unassigned local variable 'a'». Это является главным отличием ref от out.

Ключевое слово out

Out используется точно таким же образом как и ref, за исключением того, что параметр не обязан быть проинициализирован перед передачей, но при этом в методе переданному параметру обязательно должно быть присвоено новое значение:

public static void ChangeValue(out int a)
{
   a = 2;
}
static void Main(string[] args)
{
   int a;
   ChangeValue(out a);
   Console.WriteLine(a); // 2
   Console.ReadLine();
}

Если не присвоить новое значение параметру out, мы получим ошибку «The out parameter 'a' must be assigned to before control leaves the current method»

Производительность

Учитывая тот факт, что по умолчанию в метод передаются параметры по значению и создаются их копии в стеке, при использовании сложных типов данных (пользовательские структуры), или если метод вызывается много раз, это плохо скажется на производительности. В таком случае также стоит использовать ключевые слова ref и out.

Если говорить в целом о ссылочных типах и типах значений, то производительность приложения упадет, если использовать только ссылочные типы. На создание переменной ссылочного типа в куче выделяется память под данные, а в стеке под ссылку на эти данные. Для типов значений память выделяется только в стеке. Время на размещение данных в стеке меньше, чем в куче, это также идет в плюс типам значений в плане производительности.
Понравилась статья? Подпишись на рассылку и узнавай первым о новых уроках по почте!


Поделиться с друзьями:
26 авг 2014 17:04
CurtisTrody 18 авг 2017 12:51
Мы ценим ваше время и делим с вами общие цели. Ваши продажи для нас главный приоритет.
заказать продвижение интернет магазина логин скайпа SEO2000

оращайтесь договримся есть примеры работ логин скайпа SEO2000

Ilya 29 июл 2017 13:34
Большое спасибо за урок!

RobertAttar 27 июн 2017 14:37
Мы ценим ваше время и делим с вами общие цели. Ваши продажи для нас главный приоритет.
продвижение групп в контакте логин скайпа SEO2000

оращайтесь договримся есть примеры работ логин скайпа SEO2000

Artem_86 13 апр 2017 14:56
Помогите пожалуйста понять до конца.
1.)При передаче переменной в метод по ссылке в функцию передается не
значение переменной,а ее адрес в памяти.Я правильно понимаю?
2.)когда в методе я хочу поменять значения 2-х перем.местами,передавая их в функцию по ссылке:
public void func(ref int x,ref int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
static void Main(string[] args)
{
int a = 1;
int b = 2;
func(ref a , ref b);
...
} переменные в функции поменяются адрессами и соответственно значениями?т.е.переменная а,со значением 1,теперь имеет адресс переменной b у которой значение 2,а переменная b имеет адрес а.Поэтому теперь а == 2 ,а b == 1.Я правильно понимаю?

http://www.maillotdefoot-euro.com/maillot-psg-c-3_15/ 23 фев 2017 11:02
I would like this!!!

VipUserca 15 фев 2017 07:54
I found a great shop cc wucshop.com What do you think?

bas-tion.ru 12 май 2016 22:36
Из урока понял что:
Out присваивает внутренней переменной ссылку на данные от внешней переменной, а ref наоборот, внешнюю переменную ссылает на себя

Oper 10 фев 2015 09:40
pinguin-linuxoid
---

Методы можно условно подразделить на функции и процедуры. Функции это такие методы, которые возвращают значение после завершения, а процедуры, это методы, которые не возвращают значения после завершения. В C# нет разделения на функции и процедуры т.к. если нам не нужно что бы метод возвращал значение, мы пишем void, который в свою очередь возвращает ничего.

Как я слышал, что сейчас хорошей практикой считается создавать методы, которые возвращают void, а если требуется возвращать данные из метода, то нужно методу передать переменную в виде параметра с приставкой out(или ref, если переменную нужно не только возвращать, но и принять в метод). Поправьте, если я в чем то ошибаюсь.

Максим 29 дек 2014 13:21
pinguin-linuxoid
---
В C# не используются термины функция и процедура, здесь только методы. В других языках процедура не возвращает значение, функция - возвращает

pinguin-linuxoid 28 дек 2014 22:17
Спасибо за полезный урок. Как я понял без ref или out наш метод - процедура а с ними - функция?

Диманиак 10 дек 2014 18:05
жаль нет задания для этого урока

Иван 14 окт 2014 06:51
Спасибо за урок!
У вас ошибочка: список ссылочных типов озаглавлен "К типам значений относятся"

Иван 06 окт 2014 15:03
Интересненько... спасибо за урок

Sergey 27 сен 2014 09:11
Спасибо за урок


Добавить комментарий:

Имя (обязат.)
E-mail (обязат., не публикуется)


Для вставки ваших программ пользуйтесь кнопкой "исходный код"
Вёрстка сайта с нуля

Уникальный Видеокурс!

"Научись верстать сайты и заработай на этом!"

Получить видеокурс

Подпишись на курс по программированию, и узнавай первым о новых уроках!

RSS подписка Страничка Вконтакте Мы в Twitter

Ошибка в тексте? Выделите ее мышкой и нажмите Ctrl+Enter
Поблагодарить автора: Номер карты (ПриватБанк)
5168 7572 4170 8660
WebMoney
R372544961915 U685637142028 Z999792764387
Наверх
Система Orphus