|
|
Регистрация Восстановить пароль |
Регистрация | Задать вопрос |
Заплачу за решение |
Новые сообщения |
Сообщения за день |
Расширенный поиск |
Правила |
Всё прочитано |
|
Опции темы | Поиск в этой теме |
02.01.2018, 00:46 | #1 |
Пользователь
Регистрация: 19.08.2014
Сообщений: 16
|
Разница между ссылочными и значимыми типами и связанные с этим вопросы
Здравствуйте уважаемые форумчане. Есть один не совсем понятный для меня скажем так общетеоретический вопрос, связанный с различием между типами значения и ссылочными типами в .net. Заранее извиняюсь за развернутый вопрос, т.к. не могу изложить его лаконично. Но хотелось бы полной ясности т.к. в литературе не все это отражено так подробно, как мне бы хотелось.
Для отправной точки возьму пример из Альбахари: С помощью ключевого слова struct можно определить специальный тип значения (рис. 2.1) public struct Point { public int X, Y;} Рис.2.1.jpg Присваивание экземпляра типа значения всегда приводит к копированию экземпляра. Например: static void Main() { Point p1= new Point(); p1.X=7; Point p2=p1; Console.WriteLine(p1.X) //7 Console.WriteLine(p2.X) //7 p1.X=9; Console.WriteLine(p1.X) //9 Console.WriteLine(p2.X) //7 } На рис. 2.2 видно, что p1 и p2 имеют независимые хранилища Рис.2.2.jpg Ссылочный тип сложнее типа значения и предполагает наличие двух частей: объекта и ссылки на этот объект. Содержимое переменной или константы, относящейся к ссылочному типу — это ссылка на объект, который содержит значение. Перепишем тип Point из предыдущего примера в виде класса, а не структуры (рис. 2.3): public class Point { public int X, Y;} Рис.2.3.jpg Присваивание переменной ссылочного типа копирует ссылку, но не экземпляр объекта. Это позволяет множеству переменных ссылаться на один и тот же объект - то, что обычно невозможно с типами значений. Если повторить предыдущий пример при условии, что Point теперь является классом, операция над р1 оказывает влияние на p2: static void Main() { Point pl = new Point() ; pl.X = 7; Point p2 = pl; // Копирует ссылку на pl Console.WriteLine (pl.X); // 7 Console.WriteLine (p2.X); // 7 pl.X = 9; // Изменить pl.X Console.WriteLine (pl.X); // 9 Console.WriteLine (p2.X); // 9 } Ha рис. 2.4 видно, что р1 и p2 — это две ссылки, указывающие на один и тот же объект. Рис.2.4.jpg Хорошо, с теорией закончили. Дальше сам вопрос. Единственно только отмечу для себя, что на рис. 2.4 p2 получает ссылку не на p1, а на то, что помечено словом объект. Может быть в этом частично и ответ на мой вопрос. Итак вопрос. Есть следующий простой «учебный» код, писал сам, не критикуйте сильно в т.ч. и за форматирование. Есть три класса (на то, что они private не заостряйте внимания). A и B – совсем примитивные, а класс Identifier – чтобы создать объект-идентификатор - каждый новый создаваемый объект Identifier-а получает на 1 больший ID, чем предыдущий. private class A { public object X; } private class B { public object Y; } private class Identifier { private static int count = 0; public int ID = 0; public Identifier() { count++; ID = count; } } И вот их использование, скажем в методе Main: var a = new A(); var b = new B(); var i1 = new Identifier(); var i2 = new Identifier(); var i3 = new Identifier(); a.X = i1; var c = a.X; b.Y = a.X; a.X = i3; Debug.WriteLine(string.Format("i1={ 0}, i2={1}, i3={2}",i1.ID, i2.ID, i3.ID)); Debug.WriteLine(string.Format("(a.X ).ID={0}, (c=a.X).ID={1}, (b.Y=a.X).ID={2}", ((Identifier)a.X).ID, ((Identifier)c).ID, ((Identifier)b.Y).ID)); И вот результат вывода программы: i1=1, i2=2, i3=3 (a.X).ID=3, (c=a.X).ID=1, (b.Y=a.X).ID=1 В первой строке я просто проверяю, что мои объекты идентификаторы работают правильно т.е. получают новые ID. Вопрос заключается в следующем: почему при изменении ссылки a.X с объекта i1 на объект-идентификатор i3, другие переменные (c и b.Y) не стали автоматически ссылаться тоже на i3, а остались ссылаться по-прежнему на i1, хотя c=a.X и b.Y=a.X? Может кому-то этот вопрос покажется глупым, но получается что до присваивания a.X = i3, сразу три переменные a.X, c, b.Y ссылались на объект i1, после присваивания a.X = i3, две переменные (с, b.Y) остались ссылаться на i1. Т.е. они изначально ссылались на i1, а не на a.X, так получается? Из этого всего у меня вытекает один важный для меня вопрос из-за которого я и создал эту тему. Предположим для работы программы нужно создать, инициализировать два класса. Сперва один, скажем FirstClass, который осуществляет первичную обработку (считывание) информации и заполняет данными массивы, списки типа List<T>, другие данные. В процессе работы экземпляра класса FirsClass (firstCl) в нем накапливается значительный объем информации. После обработки этих данных для работы программы необходимо передать часть этой информации в экземпляр SecondClass для ее конечной обработки в соответствие с некоторой специфичной логикой. Так вот вопрос: Если 1) данные из firstCl (например несколько массивов, списков – например list=new List<double[]>()) передаются в экземпляр SecondClass (secondCl). После этого firstCl становится «ненужным» 2) затем на firstCl вызывается метод Dispose класса FirstClass (а в Dispose скажем вызывается метод list.Clear()) 3) будут ли данные, переданные из firstCl в secondCl, например ссылка на тот же list в каком-нибудь private поле SecondClass-а все еще доступными в нормальном (не обнуленном) виде объекту secondCl? Или после выполнения firstCl.Dispose() эти данные потеряются(получат ссылки на null) и в экземпляре secondCl. По логике ничего такого боятся не стоит, но хотелось бы узнать у "знающих". Спасибо за ответ! Последний раз редактировалось Sallivan_Bidl; 02.01.2018 в 00:50. |
02.01.2018, 23:36 | #2 | |||
Старожил
Регистрация: 28.01.2009
Сообщений: 21,000
|
Цитата:
Цитата:
в данном случае вы можете просто FirstClass передать внутрь SecondClass. Цитата:
ссылка на ссылку обычно не существует.(разве что ref/out параметры из обыденного) Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел. Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите. |
|||
03.01.2018, 00:43 | #3 | |
Пользователь
Регистрация: 19.08.2014
Сообщений: 16
|
Цитата:
"сырыми" данными, нужными только внутри методов самого класса. Пришла в голову мысль, если в том же методе Dispose сделать например не list.Clear(), а list=null, т.е. я занулю ссылку самой переменной list в объекте firstCl и что при этом произойдет: я просто потеряю ссылку на список? А поскольку у меня на сам лист есть ссылка в другом объекте (secondCl - например в переменной listSecCl), то listSecCl не будет null, или будет? Видимо надо проверить на практике. Последний раз редактировалось Sallivan_Bidl; 03.01.2018 в 02:48. |
|
03.01.2018, 12:57 | #4 |
Старожил
Регистрация: 28.01.2009
Сообщений: 21,000
|
не будет, с чего вдруг?
сами ссылки не связаны, у вас же на диаграмме 4 нет связей между ссылками Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел. Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите. |
04.01.2018, 06:09 | #5 |
Пользователь
Регистрация: 19.08.2014
Сообщений: 16
|
Спасибо, теперь вроде все понял.
|
Похожие темы | ||||
Тема | Автор | Раздел | Ответов | Последнее сообщение |
Разница между числами | businessman | Паскаль, Turbo Pascal, PascalABC.NET | 6 | 21.05.2015 12:55 |
разница между компами | новая | Компьютерное железо | 1 | 20.11.2011 12:33 |
В чем разница между С и С++? | Freddy Krjuger | Общие вопросы C/C++ | 1 | 14.11.2009 21:23 |
Разница между датами | kykysya | Общие вопросы Delphi | 8 | 26.03.2009 18:22 |