Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.68/19: Рейтинг темы: голосов - 19, средняя оценка - 4.68
2 / 2 / 0
Регистрация: 26.09.2014
Сообщений: 45

Не во всех случаях работает передача объекта в метод по ссылке

09.08.2015, 17:51. Показов 3772. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем нам известно, что классы - это ссылочный тип данных и передавая экземпляр класса в метод, он передается по ссылке. Если метод внесет какие-то изменения в этот экземпляр, то по выходу из метода, изменения сохранятся. Но, как оказалось, почему-то это не всегда это так!
Ниже я привел простенький пример, поведение которого мне не понятно и требуется ваша помощь!
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using System;
 
namespace ConsoleApplication1
{
    class Program
    {
        public class ClassA
        {
            public ClassA(int value) { SomeVar = value; }
            public int SomeVar { get; set; }
        }
 
        public class ClassB
        {
            public void DoSomethingWithClassA(ClassA obj) { obj.SomeVar++; }
            public void DoNotWorkMethod(ClassA obj)
            {
                var newObj = new ClassA(500);
                obj = newObj;
            }
            public void DoNotWorkMethod2(ClassA obj) { obj = someObj; }
        }
 
        public static ClassA someObj = new ClassA(1000);
 
        static void Main(string[] args)
        {
            var objClassA = new ClassA(100);
            Console.WriteLine("Before: {0}", objClassA.SomeVar);
 
            var objClassB = new ClassB();
            objClassB.DoSomethingWithClassA(objClassA);
            Console.WriteLine("After DoSomethingWithClassA(...): {0}", objClassA.SomeVar);
            //Before: 100
            //After DoSomethingWithClassA(...): 101
            //Тут все здорово и передача по ссылке работает
 
            objClassB.DoNotWorkMethod(objClassA);
            Console.WriteLine("After DoNotWorkMethod(...): {0}", objClassA.SomeVar);
            //Ожидаю, что значение переменной станет 500, но выводит:
            //After DoNotWorkMethod(...): 101
 
            //Может кто-то объяснить ПОЧЕМУ значение не изменилось???
            //Я сначала подумал, что переменная объявлена внутри метода и по выходу
            //из него ее время жизни закончено и сборщик мусора ее удалил.
            //Чтобы проверить это предположение добавил переменную, которая точно будет существовать.
            objClassB.DoNotWorkMethod2(objClassA);
            Console.WriteLine("After DoNotWorkMethod2(...): {0}", objClassA.SomeVar);
            //Ожидаю, что уж тут-то точно изменится значение на 1000, но нет! Выводит это:
            //After DoNotWorkMethod2(...): 101
        }
    }
}
Может кто-то объяснить что не так? Нужно именно объяснение: внятное и доходчивое! По какой причине во втором и третьем методе значение не изменилось? Я искренне не понимаю. Ячейка стека, которая содержит ссылку на объект objClassA в куче и по выходу содержит ссылку на этот объект. Но ведь объект внутри метода подменен. Почему же не сработало?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
09.08.2015, 17:51
Ответы с готовыми решениями:

Передача объекта по ссылке
В книге Шилдта есть задание: #include <iostream> #include <cstring> #include <cstdlib> using namespace std; class...

Передача объекта по ссылке
Не работает передача константы по ссылке. Ошибка: "error: passing ‘const std::allocator<int>’ as ‘this’ argument discards qualifiers "...

Передача объекта по ссылке
Уважаемые товарисчи, помогите разобраться с базовой вещью! Дело в том, что немного запутался. Мы знаем, что объекты передаются в...

5
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
09.08.2015, 18:08
Лучший ответ Сообщение было отмечено Памирыч как решение

Решение

Цитата Сообщение от Scandal777 Посмотреть сообщение
Может кто-то объяснить что не так?
В метод передается копия переменной.

Переменная — это место хранения информации.
Есть переменные значимых типов, а есть переменные ссылочных типов.
В переменных значимых типов хранится значение.
В переменных ссылочных типов хранится ссылка на значение.

При присваивании, передаче в метод или при возврате из него создается копия переменной.
Если переменная значимого типа, то создается копия всего значения.
Если переменная ссылочного типа, то создается копия ссылки на то же самое значение.
2
2 / 2 / 0
Регистрация: 26.09.2014
Сообщений: 45
09.08.2015, 19:49  [ТС]
Цитата Сообщение от kolorotur Посмотреть сообщение
Если переменная ссылочного типа, то создается копия ссылки на то же самое значение.
Спасибо огромное. Вот этого я не знал. Я думал, что передается та же ячейка.
Т.е. получается, что фактически у нас есть две разные ячейки стека, которые указывают на один и тот же объект в куче. Тогда становится понятным, почему не сработали второй и третий методы, т.к. копии присвоили адрес на другой объект. По выходу из метода копию убили, а настоящая ячейка стека как была неизменной, так и осталась.
Тогда вопрос: что нужно сделать, чтобы по выходу из второго или третьего метода изменения сохранились? Ref и out не рассматриваем. Я так понимаю, что у копии нужно взять адрес через &, а затем разыменовывать. Так будет получен указатель на ячейку в куче. Затем нужно взять от нее адрес и в эту ячейку запись нужный объект. Но словах все вроде просто, но у меня так и не получилось подменить объект по адресу, на который ссылаются обе ячейки (оригинал и копия).
Если кто-то смог провернуть - покажите как! Очень интересно!
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
09.08.2015, 20:36
Лучший ответ Сообщение было отмечено Памирыч как решение

Решение

Цитата Сообщение от Scandal777 Посмотреть сообщение
фактически у нас есть две разные ячейки стека, которые указывают на один и тот же объект в куче.
Не стоит пользоваться понятиями стек и куча, когда речь идет о ссылочных или значимых типах.
Место хранения практически никак не связано с типом переменной (иначе они бы назывались стековые и кучевые, а не значимые и ссылочные).
Стек — это вообще не более чем оптимизация, причем вовсе не обязательная.

Цитата Сообщение от Scandal777 Посмотреть сообщение
что нужно сделать, чтобы по выходу из второго или третьего метода изменения сохранились? Ref и out не рассматриваем.
Почему не рассматриваем ref и out?
Они для этого и сделаны.

Если не нравятся ref с out, то делайте запаковку:
C#
1
2
3
4
5
6
7
8
9
class Box<T>
{
   public T Value { get; set; }
 
   public Box(T value)
   {
     this.Value = value;
   }
}
В метод уже передавайте упакованное значение и присваивайте в нем свойству Value новое значение.

Цитата Сообщение от Scandal777 Посмотреть сообщение
Я так понимаю, что у копии нужно взять адрес через &, а затем разыменовывать.
Ссылка — это не указатель, не путайте.
В .NET ссылка — это что-то вроде дескриптора: "номерка", с помощью которого рантайм знает, доступ к какому объекту вы хотите получить. Примерно как при открытии файла, вы получаете дескриптор: просто номер, с помощью которого ОС позволяет получать доступ к содержимому диска.
По факту, конечно, ссылка реализована через указатели, но это лишь деталь реализации, которая может меняться.

Цитата Сообщение от Scandal777 Посмотреть сообщение
что нужно сделать, чтобы по выходу из второго или третьего метода изменения сохранились?
Использовать ref/out или запаковывать переменную в ссылочный тип предложенным выше способом.
0
2 / 2 / 0
Регистрация: 26.09.2014
Сообщений: 45
09.08.2015, 20:47  [ТС]
Цитата Сообщение от kolorotur Посмотреть сообщение
Почему не рассматриваем ref и out?
Они для этого и сделаны.
Да просто научный интерес и любопытство. Если в копии ячейки ссылка на объект, то хочется понять, можно ли как-то подменить этот объект. В плюсах я бы за пару секунд такую штуку провернул, а тут иначе. Тут получается, что сам объект изменять можно и никакие ref/out не нужны, а подменить объект либо нельзя, либо это фантастический геморрой и приходится ref/out писать.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
09.08.2015, 20:55
Цитата Сообщение от Scandal777 Посмотреть сообщение
В плюсах я бы за пару секунд такую штуку провернул, а тут иначе.
Здесь тоже пара секунд: достаточно дописать ref перед параметром метода.
Ну да, на два символа больше, чем амперсанд в плюсах. Big deal.

Цитата Сообщение от Scandal777 Посмотреть сообщение
Тут получается, что сам объект изменять можно и никакие ref/out не нужны, а подменить объект либо нельзя, либо это фантастический геморрой и приходится ref/out писать.
Дык в плюсах то же самое: если вы передаете указатель (*), то передается копия указателя. Так реализована передача ссылок в шарпе.
Если передается адрес (&), то передается собственно адрес переменной, то есть фактически создается альяс для передаваемой переменной. Семантически абсолютно то же самое, что ref, с разницей в минус два символа.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
09.08.2015, 20:55
Помогаю со студенческими работами здесь

Передача объекта структуры по ссылке
Здравствуйте. Нужно использовать передачу структуры по ссылке(или по указателю). Объясните пожалуйста как это делать и , если можно, как...

Передача поля объекта по ссылке
Делаю курсовую через костыли, для плавной анимации сделал функцию, одним из аргументов которой является число, которое увеличивается внутри...

Передача объекта по ссылке или о значению
Да, да, снова этот вопрос. Допустим у меня есть объект Student с полями String surname и String name. Этот объект лежит двух разных листах....

Передача объекта-наследника по r-value ссылке на родительский класс
Здоровеньки булы. Собственно, код: class x { protected: int a; public: x() {} x(int i) : a(i) {} x(const x&amp;...

Стек, не во всех случаях работает удаление
Описать класс Lifo, реализовать стек произвольного размера для хранения целых чисел, добавление и извлечение одиночного элемента из стека,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru