HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-21
1 <p><a>#статьи</a></p>
1 <p><a>#статьи</a></p>
2 <ul><li>4 сен 2019</li>
2 <ul><li>4 сен 2019</li>
3 <li>0</li>
3 <li>0</li>
4 </ul><p>Только работа с объектами начинает казаться простой, как тут же появляются новые сюрпризы. Рассказываем, как их избежать.</p>
4 </ul><p>Только работа с объектами начинает казаться простой, как тут же появляются новые сюрпризы. Рассказываем, как их избежать.</p>
5 <p> vlada_maestro / shutterstock</p>
5 <p> vlada_maestro / shutterstock</p>
6 <p>Пишет о программировании, в свободное время создаёт игры. Мечтает открыть свою студию и выпускать ламповые RPG.</p>
6 <p>Пишет о программировании, в свободное время создаёт игры. Мечтает открыть свою студию и выпускать ламповые RPG.</p>
7 <p>Данные, с которыми работает программа, хранятся в оперативной памяти. Для этого используются ячейки, у которых есть адрес (ключ) и значение.</p>
7 <p>Данные, с которыми работает программа, хранятся в оперативной памяти. Для этого используются ячейки, у которых есть адрес (ключ) и значение.</p>
8 <p>Раньше программистам приходилось запоминать эти ключи или записывать их в отдельный блокнот. Но современные языки программирования позволяют создавать переменные (их называют примитивными или значимыми типами данных), у которых вместо адреса идентификатор:</p>
8 <p>Раньше программистам приходилось запоминать эти ключи или записывать их в отдельный блокнот. Но современные языки программирования позволяют создавать переменные (их называют примитивными или значимыми типами данных), у которых вместо адреса идентификатор:</p>
9 int sum = 50; //sum - ключ, 50 - значение string name = "John";<p>Для каждой переменной выделяется одна ячейка памяти. Однако объекты гораздо больше обычной переменной, потому что в них может быть сразу несколько полей. Можно создать переменную<em>hero</em>, в которой будет объект класса<em>Character</em>:</p>
9 int sum = 50; //sum - ключ, 50 - значение string name = "John";<p>Для каждой переменной выделяется одна ячейка памяти. Однако объекты гораздо больше обычной переменной, потому что в них может быть сразу несколько полей. Можно создать переменную<em>hero</em>, в которой будет объект класса<em>Character</em>:</p>
10 Character hero = new Character();<p>Но в ней будет храниться не сам объект, а ссылка на него. Поэтому объекты относятся к ссылочным типам данных, и из-за этого работа с ними отличается от работы с примитивными типами.</p>
10 Character hero = new Character();<p>Но в ней будет храниться не сам объект, а ссылка на него. Поэтому объекты относятся к ссылочным типам данных, и из-за этого работа с ними отличается от работы с примитивными типами.</p>
11 <p>Рассмотрим такой код:</p>
11 <p>Рассмотрим такой код:</p>
12 Character hero = new Character("Player", 50, 20); Character hero1 = new Character("Player", 50, 20); if (hero == hero1) { Console.WriteLine("true"); } else { Console.WriteLine("false"); } Console.ReadKey();<p>Здесь сначала создаются, а потом сравниваются два идентичных объекта. Если они равны, то выводится<em>true</em>, а иначе -<em>false</em>. Вот что выведет программа:</p>
12 Character hero = new Character("Player", 50, 20); Character hero1 = new Character("Player", 50, 20); if (hero == hero1) { Console.WriteLine("true"); } else { Console.WriteLine("false"); } Console.ReadKey();<p>Здесь сначала создаются, а потом сравниваются два идентичных объекта. Если они равны, то выводится<em>true</em>, а иначе -<em>false</em>. Вот что выведет программа:</p>
13 <p>Несмотря на то что все поля совпадают, программа выводит<em>false</em>. И это не баг. Дело в том, что сравниваются не значения полей объектов, а ссылки на них. А поскольку это два различных объекта, то и адреса у них разные.</p>
13 <p>Несмотря на то что все поля совпадают, программа выводит<em>false</em>. И это не баг. Дело в том, что сравниваются не значения полей объектов, а ссылки на них. А поскольку это два различных объекта, то и адреса у них разные.</p>
14 <p>Строка<em>true</em>будет выведена только в том случае, если в обеих переменных находится ссылка на один и тот же объект. Чтобы это проверить, в коде из примера выше нужно изменить значение переменной<em>hero1</em>:</p>
14 <p>Строка<em>true</em>будет выведена только в том случае, если в обеих переменных находится ссылка на один и тот же объект. Чтобы это проверить, в коде из примера выше нужно изменить значение переменной<em>hero1</em>:</p>
15 <p>Теперь программа выведет<em>true</em>, потому что это один и тот же объект:</p>
15 <p>Теперь программа выведет<em>true</em>, потому что это один и тот же объект:</p>
16 <p>И теперь, если изменить<em>hero1</em>,<em>hero</em>тоже изменится:</p>
16 <p>И теперь, если изменить<em>hero1</em>,<em>hero</em>тоже изменится:</p>
17 Character hero = new Character("Player", 50, 20); Character hero1 = hero; hero1.Move("up"); Console.WriteLine(hero.Coordinates); Console.ReadKey();<p>Тут меняются координаты объекта<em>hero1</em>с помощью метода<em>Move ()</em>, а затем выводятся координаты объекта<em>hero</em>. Они были [50, 20], но теперь по оси Y значение будет 21:</p>
17 Character hero = new Character("Player", 50, 20); Character hero1 = hero; hero1.Move("up"); Console.WriteLine(hero.Coordinates); Console.ReadKey();<p>Тут меняются координаты объекта<em>hero1</em>с помощью метода<em>Move ()</em>, а затем выводятся координаты объекта<em>hero</em>. Они были [50, 20], но теперь по оси Y значение будет 21:</p>
18 <p>Если нужно проверить, совпадают ли значения полей у объектов, то надо вручную проверять каждое поле:</p>
18 <p>Если нужно проверить, совпадают ли значения полей у объектов, то надо вручную проверять каждое поле:</p>
19 if (hero.X == hero1.X &amp;&amp; hero.Y == hero1.Y) { Console.WriteLine("true"); } else { Console.WriteLine("false"); }<p>Однако это неудобно, если полей очень много. Чтобы упростить эту задачу, можно использовать метод<em>Equals ()</em> - его мы рассмотрим в статье про полиморфизм. Если же надо сделать копию, то можно написать метод<em>Clone ()</em>или<em>Copy ()</em>. Он будет принимать объект, чтобы скопировать его данные:</p>
19 if (hero.X == hero1.X &amp;&amp; hero.Y == hero1.Y) { Console.WriteLine("true"); } else { Console.WriteLine("false"); }<p>Однако это неудобно, если полей очень много. Чтобы упростить эту задачу, можно использовать метод<em>Equals ()</em> - его мы рассмотрим в статье про полиморфизм. Если же надо сделать копию, то можно написать метод<em>Clone ()</em>или<em>Copy ()</em>. Он будет принимать объект, чтобы скопировать его данные:</p>
20 public void Clone(Character obj) { this.name = obj.name; this.x = obj.x; this.y = obj.y; this.health = obj.health; }<p>Или же можно написать конструктор, который будет принимать в качестве аргумента другой объект.</p>
20 public void Clone(Character obj) { this.name = obj.name; this.x = obj.x; this.y = obj.y; this.health = obj.health; }<p>Или же можно написать конструктор, который будет принимать в качестве аргумента другой объект.</p>
21 <p>Сразу же стоит отметить, что у передачи объекта в качестве аргумента есть побочные эффекты. Рассмотрим такой код:</p>
21 <p>Сразу же стоит отметить, что у передачи объекта в качестве аргумента есть побочные эффекты. Рассмотрим такой код:</p>
22 static void Main(string[] args) { int num = 2; Multiply(num); Console.WriteLine(num); Console.ReadKey(); } private static void Multiply(int num) { num *= 2; }<p>В методе<em>Multiply ()</em>полученное число умножится на два. Но так как<em>int</em> - это значимый тип, то в метод будет передана не ссылка на это значение в памяти, а само число. То есть будет создана новая переменная (их называют локальными) с таким же значением, и уже она будет умножена на два. На переданное значение это никак не повлияет.</p>
22 static void Main(string[] args) { int num = 2; Multiply(num); Console.WriteLine(num); Console.ReadKey(); } private static void Multiply(int num) { num *= 2; }<p>В методе<em>Multiply ()</em>полученное число умножится на два. Но так как<em>int</em> - это значимый тип, то в метод будет передана не ссылка на это значение в памяти, а само число. То есть будет создана новая переменная (их называют локальными) с таким же значением, и уже она будет умножена на два. На переданное значение это никак не повлияет.</p>
23 <p>Вот что выведет программа:</p>
23 <p>Вот что выведет программа:</p>
24 <p>Однако если использовать объект, то будет передана ссылка на него, а все операции будут проводиться с ним, а не с его значением:</p>
24 <p>Однако если использовать объект, то будет передана ссылка на него, а все операции будут проводиться с ним, а не с его значением:</p>
25 static void Main(string[] args) { Character hero = new Character(50, 20); Change(hero); Console.WriteLine(hero.Health); Console.ReadKey(); } private static void Change(Character hero) { hero.Health = 4; }<p>Вот что выведет программа:</p>
25 static void Main(string[] args) { Character hero = new Character(50, 20); Change(hero); Console.WriteLine(hero.Health); Console.ReadKey(); } private static void Change(Character hero) { hero.Health = 4; }<p>Вот что выведет программа:</p>
26 <p>Такие особенности ссылочных типов нужно учитывать при разработке программ, чтобы не происходило ничего неожиданного. Например, когда значение меняется, хотя и не должно.</p>
26 <p>Такие особенности ссылочных типов нужно учитывать при разработке программ, чтобы не происходило ничего неожиданного. Например, когда значение меняется, хотя и не должно.</p>
27 <p>Создайте класс Game, в котором будут храниться все игровые объекты. Дайте персонажу возможность перемещаться по карте и взаимодействовать с объектами, координаты которых совпадают с его позицией.</p>
27 <p>Создайте класс Game, в котором будут храниться все игровые объекты. Дайте персонажу возможность перемещаться по карте и взаимодействовать с объектами, координаты которых совпадают с его позицией.</p>
28 <p><strong>Подсказка</strong></p>
28 <p><strong>Подсказка</strong></p>
29 <p><strong>Используйте коллекции и циклы.</strong></p>
29 <p><strong>Используйте коллекции и циклы.</strong></p>
30 <p>Практикуйтесь и работайте с объектами как можно чаще, и тогда вы сможете овладеть ими. Однако, чтобы писать код без костылей, нужно понимать, как он работает, - в том числе это касается и ссылочных, и значимых типов данных. Кроме того, понимание различий между этими типами избавит вас от неприятных сюрпризов.</p>
30 <p>Практикуйтесь и работайте с объектами как можно чаще, и тогда вы сможете овладеть ими. Однако, чтобы писать код без костылей, нужно понимать, как он работает, - в том числе это касается и ссылочных, и значимых типов данных. Кроме того, понимание различий между этими типами избавит вас от неприятных сюрпризов.</p>
31 <a><b>Бесплатный курс по Python ➞</b>Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу</a>
31 <a><b>Бесплатный курс по Python ➞</b>Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу</a>