Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.53/34: Рейтинг темы: голосов - 34, средняя оценка - 4.53
8 / 8 / 0
Регистрация: 02.09.2013
Сообщений: 131
1

Создание объектов в цикле

10.11.2017, 09:32. Показов 6534. Ответов 15
Метки нет (Все метки)

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

C#
1
2
3
4
5
6
7
            for (int i = 0; i < 7; i++)
            {
                StringBuilder stroka = new StringBuilder();
                stroka.Append("hello");
                
                Console.WriteLine(stroka.ToString());
            }
Вот.. Почему так можно? А, скажем, вот так, нельзя

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
            
                StringBuilder stroka = new StringBuilder();
                stroka.Append("hello");
                
                Console.WriteLine(stroka.ToString());
 //----------------------------------------
                StringBuilder stroka = new StringBuilder();
                stroka.Append("hello");
                
                Console.WriteLine(stroka.ToString());      
//---------------------------------------      
                StringBuilder stroka = new StringBuilder();
                stroka.Append("hello");
                
                Console.WriteLine(stroka.ToString());

Я в недоумени... причем, когда объекты созданы в цикле, они все живут до конца выполнения программы, то есть, каждый новосозданный не заменяет предыдущий... Как это всё выглядит? Помогите понять... И как обратиться после цикла к какому-то из созданных объектов? Ведь я вижу одно имя для всех, а это скорее всего не так..
__________________
Помощь в написании контрольных, курсовых и дипломных работ здесь
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
10.11.2017, 09:32
Ответы с готовыми решениями:

Создание объектов класса в цикле
Помогите, пожалуйста, с задачей. Создать приложение (Console Application), в котором в цикле...

События для объектов в цикле
Здравствуйте! Подскажите пожалуйста, как нужно правильно написать, что бы к каждому объекту...

в цикле создать несколько объектов с разными именами
Добрый день! Подскажите пожалуйста как в цикле создать несколько объектов с разными именами,...

Как менять свойства сразу нескольких объектов в цикле?
Суть в том, что у меня много numericUpDown и один CheckBox. При установки значения...

15
598 / 482 / 185
Регистрация: 19.04.2016
Сообщений: 1,885
10.11.2017, 09:36 2
Цитата Сообщение от PaskalisT Посмотреть сообщение
C#
1
2
3
4
5
6
7
8
9
10
11
StringBuilder stroka = new StringBuilder();
                stroka.Append("hello");
Console.WriteLine(stroka.ToString());
 //----------------------------------------
                StringBuilder stroka = new StringBuilder();
                stroka.Append("hello");
Console.WriteLine(stroka.ToString());      
//---------------------------------------      
                StringBuilder stroka = new StringBuilder();
                stroka.Append("hello");
Console.WriteLine(stroka.ToString());
Так можно, но не нужно...
C#
1
2
3
4
5
6
7
8
9
10
11
StringBuilder stroka = new StringBuilder();
                stroka.Append("hello");
Console.WriteLine(stroka.ToString());
 //----------------------------------------
                stroka = new StringBuilder();
                stroka.Append("hello");
Console.WriteLine(stroka.ToString());      
//---------------------------------------      
                stroka = new StringBuilder();
                stroka.Append("hello");
Console.WriteLine(stroka.ToString());
0
20 / 35 / 14
Регистрация: 08.10.2015
Сообщений: 406
10.11.2017, 09:37 3
Но вот i тоже определяется на каждой итерации.
Цитата Сообщение от PaskalisT Посмотреть сообщение
for (int i = 0; i < 7; i++)
Ведь можно i и за пределами цикла определить один раз. Так что не только объекты по новой определяются на каждом шаге
0
8 / 8 / 0
Регистрация: 02.09.2013
Сообщений: 131
10.11.2017, 09:44  [ТС] 4
Так можно, но не нужно...

C#
1
2
3
4
5
6
7
8
9
10
11
StringBuilder stroka = new StringBuilder();
                stroka.Append("hello");
Console.WriteLine(stroka.ToString());
 //----------------------------------------
                stroka = new StringBuilder();
                stroka.Append("hello");
Console.WriteLine(stroka.ToString());      
//---------------------------------------      
                stroka = new StringBuilder();
                stroka.Append("hello");
Console.WriteLine(stroka.ToString());
А как в таком случае обратиться к объекту, например, который первый раз создался?
0
187 / 175 / 111
Регистрация: 22.06.2009
Сообщений: 533
10.11.2017, 09:48 5
EveKS, тут видимо вопрос был, почему в цикле можно множество раз объявлять и инициализировать переменную с одним и тем же именем, а вне цикла нет.
Имхо, я думаю это фича такая компилятора.. во время итерации повторное объявление отбрасывается..

Добавлено через 2 минуты
PaskalisT, ни как, он удалился имхо..
0
8 / 8 / 0
Регистрация: 02.09.2013
Сообщений: 131
10.11.2017, 09:53  [ТС] 6
Цитата Сообщение от Aumi Посмотреть сообщение
Но вот i тоже определяется на каждой итерации.
Цитата Сообщение от PaskalisT Посмотреть сообщение
for (int i = 0; i < 7; i++)
Ведь можно i и за пределами цикла определить один раз. Так что не только объекты по новой определяются на каждом шаге
точно... но почему в циклах так можно? И как это выглядит глубже? Я всегда думал, что цикл это просто повтор кода в теле и можно это код переписать также самому несколько раз и будет тоже самое

Добавлено через 4 минуты
Цитата Сообщение от worldown Посмотреть сообщение
тут видимо вопрос был, почему в цикле можно множество раз объявлять и инициализировать переменную с одним и тем же именем, а вне цикла нет.
именно так,да

Цитата Сообщение от worldown Посмотреть сообщение
ни как, он удалился имхо..
а в цикле ведь не удаляется... как я говорил про пример с многопоточность...потоки работают независимо друг от друга
0
187 / 175 / 111
Регистрация: 22.06.2009
Сообщений: 533
10.11.2017, 09:56 7
PaskalisT, ничего подобного, в цикле происходит повторная инициализация
1
8 / 8 / 0
Регистрация: 02.09.2013
Сообщений: 131
10.11.2017, 13:03  [ТС] 8
Цитата Сообщение от worldown Посмотреть сообщение
PaskalisT, ничего подобного, в цикле происходит повторная инициализация
а почему тогда поток, созданный в таком цикле продолжает работать и взаимодействовать с другим приложением, когда создается другой поток на следующих итерациях
0
Эксперт .NET
9429 / 6797 / 1092
Регистрация: 21.01.2016
Сообщений: 25,790
10.11.2017, 13:26 9
Цитата Сообщение от PaskalisT Посмотреть сообщение
Я сразу подумал, что будет ошибка, ведь создаются объекты с одинаковым именем, а так нельзя же..
C чего бы это?

Цитата Сообщение от PaskalisT Посмотреть сообщение
но почему в циклах так можно?
Потому, что переменная одна и на каждой итерации она переписывается ссылкой на новый объект.

Цитата Сообщение от PaskalisT Посмотреть сообщение
а почему тогда поток, созданный в таком цикле продолжает работать и взаимодействовать с другим приложением, когда создается другой поток на следующих итерациях
Потому, что сборщик мусора потоки не считает мусором и не трогает.
1
187 / 175 / 111
Регистрация: 22.06.2009
Сообщений: 533
10.11.2017, 14:22 10
Цитата Сообщение от Usaga Посмотреть сообщение
Потому, что сборщик мусора потоки не считает мусором и не трогает.
А я думал что сборщик мусора, собирает "мусор" только тогда когда закачаются выделенные системой ресурсы..

Добавлено через 1 минуту
PaskalisT, дайте живой пример на потоках, чего на кофейной гуще гадать..
0
Эксперт .NET
9429 / 6797 / 1092
Регистрация: 21.01.2016
Сообщений: 25,790
10.11.2017, 14:33 11
worldown, нет, он это делает, когда:
а) забивается нулевое поколение в куче;
б) его явно попросят (GC.Collect());
в) ОС не хватает памяти;
0
187 / 175 / 111
Регистрация: 22.06.2009
Сообщений: 533
10.11.2017, 14:45 12
Usaga, Да нет, это я понимаю, спасибо.. Я имел ввиду в контексте вопроса, в общем не понимаю причем тут сборщик мусора и вопрос автора..
Я без сарказма. Хочу просто понять что хочет понять автор вопроса? )
почему на выводе в цикле нет "hellohellohello..." ?
0
Эксперт .NET
9429 / 6797 / 1092
Регистрация: 21.01.2016
Сообщений: 25,790
10.11.2017, 14:48 13
worldown, автор вопроса удивляется почему объект не "пропадает" сразу же, как переписывается ссылка. Т.е. для него ссылка и сам объект - одно и то же.

Я же упомянул про сборщик в контексте того, что именно он отвечает за уборку, а не "оно само исчезает" как только ссылка переписывается и что GC уборку делает по своим правилам, а несётся всё тут же убирать, как скорая помощь.
1
[Bicycle Reinventor]
324 / 262 / 109
Регистрация: 19.10.2011
Сообщений: 668
Записей в блоге: 2
10.11.2017, 15:04 14
Цитата Сообщение от PaskalisT Посмотреть сообщение
Почему так можно? А, скажем, вот так, нельзя
Потому что существует область видимости переменных, и в одной и той же области видимости нельзя объявить две переменные с одинаковым именем. Каждый блок кода (грубо говоря пара фигурных скобок) представляет свою область видимости (вложенные друг друга или соседствующие - не важно).
Например, код:
C#
1
2
3
4
5
public void Main(){
   for(int i = 0; i < 4; i++){
      StringBuilder sb = new StringBuilder();
   }
}
имеет два блока кода - один начинается с фигурной скобки после main, другой начинается с фигурной скобки после for и является вложенным в первый. Объявление переменной sb возможно, поскольку в области видимости нет других переменных с таким же именем.

Если, как Вы говорите, переписать тот же for повтором одинаковых кусков кода, то блоков кода будет меньше, а область видимости общая:
C#
1
2
3
4
5
6
public void Main(){
      StringBuilder sb = new StringBuilder();
      StringBuilder sb = new StringBuilder();
      StringBuilder sb = new StringBuilder();
      StringBuilder sb = new StringBuilder();
}
В данном примере блок кода только один - начинается с фигурной скобки после main, и область видимости такая же. Объявление sb невозможно, поскольку в той же области видимости уже есть переменная с таким же именем.

Сравните:
C#
1
2
3
4
5
6
public void Main(){
   StringBuilder sb = new StringBuilder();
   for(int i = 0; i < 4; i++){
      StringBuilder sb = new StringBuilder();
   }
}
Такой вариант также запрещён, поскольку с точки зрения переменной внутри цикла уже существует идентификатор sb в области видимости (на уровень выше).

Так что for не просто "тупо повторяет один и тот же кусок кода несколько раз", он создаёт вложенный блок кода, для которого работают те же правила области видимости переменных, как и для любых других. И как правильно отметил Usaga, переменная в данном случае всегда одна, просто она переинициализируется на каждой итерации цикла.
1
8 / 8 / 0
Регистрация: 02.09.2013
Сообщений: 131
10.11.2017, 15:19  [ТС] 15
Я никогда не задумывался о циклах так серьезно. Ну да, они повторяют код определенное, по условию или значению, количество раз, но не более.. Работать с ними умею неплохо, со всему видами. Но сегодня ситуация с инициализацией переменных и объектов ввела меня в ступор. Ладно бы просто присваивалось новое значение переменной, но тут полностью она объявляется на каждой итерации. А, как я помню, в рамках одного контекста можно объявить поле только один раз.
Тело цикла и есть отдельный контекст и в нём на каждой итерации объявляется переменная..... Допустим, так можно только в циклах сделать, тогда мне нужно понять как это происходит, как это реализуется вне цикла(написать вручную повтор кода) что случается с объектами, созданными ранее? Мне сейчас в голову пришло этому такое объяснения, поправьте меня, если я ошибаюсь:

Допустим, есть цикл:
C#
1
2
3
4
5
6
7
8
9
10
               while (true)
               {
                                TcpClient client = listener.AcceptTcpClient();
                                ClientObject clientObject = new ClientObject(client);
 
                                // создаем новый поток для обслуживания нового клиента
                                Thread clientThread = new Thread(new ThreadStart(clientObject.process));
 
                                clientThread.Start();
                }
Опишу кратко логику кода.
Создается прослушиватель подключений клиентов client. Есть класс clientObject, взаимодействующий с клиентами в методе process. Этод метод вызывается в дополнительном потоке clientThread.
Вот... Повторюсь, что меня смутило - создание объектов с одинаковым именем в одном контексте, вопросы - что происходит с созданными объектами и как вообще представить тоже самое вне цикла, то есть, вручную переписать код...
И тут я подумал... Известно, что блок кода имеет отдельную область видимости(контекст), тогда, наверное, тело цикла можно представить как блок кода и, соответственно, количество итераций как количество таких блоков.
Например,выше описанный цикл можно представить:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
                                TcpClient client = listener.AcceptTcpClient();
                                ClientObject clientObject = new ClientObject(client);
 
                                // создаем новый поток для обслуживания нового клиента
                                Thread clientThread = new Thread(new ThreadStart(clientObject.process));
 
                                clientThread.Start();
                            }
 
                            {
                                TcpClient client = listener.AcceptTcpClient();
                                ClientObject clientObject = new ClientObject(client);
 
                                // создаем новый поток для обслуживания нового клиента
                                Thread clientThread = new Thread(new ThreadStart(clientObject.process));
 
                                clientThread.Start();
                            }
// ----------- далее такие же блоки ------------------
Вот поэтому и можно повторно объявлять объявлять объекты и переменные, так как каждая итерация в разных контекстах. И поэтому потоки не прекращают работу, переменные с одинаковыми именами ссылаются в каждом контексте на новый объект, как сказал Usaga.

Я правильно всё проанализировал?

Добавлено через 1 минуту
я пока все описал, не заметил много ответов))

Добавлено через 2 минуты
Exerion, я получается использовал основу вашего ответа, еще его не прочитав)))
0
Эксперт .NET
9429 / 6797 / 1092
Регистрация: 21.01.2016
Сообщений: 25,790
11.11.2017, 05:52 16
Цитата Сообщение от PaskalisT Посмотреть сообщение
Тело цикла и есть отдельный контекст и в нём на каждой итерации объявляется переменная.....
Переменная объявляется в нём только один раз. Точно так же как и в любом методе переменная объявляется один раз не зависимо от того, сколько раз этот метод вызывается. Вы можете вынести тело цикла в отдельный метод, если вам так понятнее будет. Разницы не будет.

Цитата Сообщение от PaskalisT Посмотреть сообщение
случается с объектами, созданными ранее?
Ничего. Они остаются в куче. А ссылки на них "затираются" вашим же кодом на следующей итерации. Компилятор не позволит вам использовать неинициализированные переменные в цикле, так что вам придётся задавать им начальные значения, которые перетрут предыдущие. А так, чисто технически и прозрачно для вас, локальные переменные цикла хранятся в стёке самого метода, где цикл расположен.

Цитата Сообщение от PaskalisT Посмотреть сообщение
Например,выше описанный цикл можно представить:
По сути - да.

Цитата Сообщение от PaskalisT Посмотреть сообщение
И поэтому потоки не прекращают работу,
А это уже неверно, потому что:
а) выход из области видимости не вызывает мгновенное уничтожение объектов ссылки на которые были потеряны;
б) CLR знает потоки "в лицо" (хранит ссылки) и не трогает их даже, когда в вашем коде уже не осталось ссылок на объекты Thread\Task и пришло время убирать мусор;

Выражатеся это в том, что если вы, к примеру, в каком-то методе создадите объект таймера и запустите его, то он продолжит работать и после выхода из метода (с учётом, что ссылок на него не осталось), но до первой сборки мусора (на самом деле останутся живы все объекты, просто по таймеру это будет явно видно). Потоки же переживут любое количество сборок мусора.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
11.11.2017, 05:52

Создание списка объектов класса с заранее неизвестным именем (именем самих объектов)
Уважаемые программисты, не получается решить такую задачу: требуется создать приложение (в консоли)...

Создание переменной в цикле
for (int i =0; i &lt; 10; i++) { int a = 10; } Почему такая запись...

Создание кнопок в цикле
Мне нужно создать кнопки в приложение в цикле. Код примерно такой: Объявляем переменную: ...

Создание потоков в цикле
В общем форумчане такая проблема. Я имею такой код: void func(string a){ *тут код... for(int...


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

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru