Непонятки со ссылками на объекты в .NET
От: justStudent  
Дата: 21.02.19 12:20
Оценка:
Добрый день!

Чувствую, что чего-то не понимаю, а вот чего...

Есть WinForms приложение, там есть некий диалог редактирования списка элементов, создаю его вот так:

MyDialog dlg = new MyDialog(objectsList);
if (dlg.ShowDialog(this) != DialogResult.OK)
 return;

saveObjects(dlg.objectsList);


В конструкторе MyDialog я просто сохраняю objectsList в переменную член класса. В самом диалоге есть кнопки add, edit, remove. Пусть пользователь нажал Remove, я удалил объект из списка, а потом пользователь нажал на Cancel в диалоге. Т.е. он не хочет удалять этот объект, вообще все действия должны быть отменены.
А по факту получается, что в objectsList уже этого объекта нет (он был удален в обработчике кнопки Remove). Как я понимаю, это из-за того, что объекты передаются по ссылке. Т.е. objectsList и dlg.objectsList указывают на один список. Как же быть в этом случае? Делаю копию списка (со всеми его элементами)? Или хранить список операций и их атрибутов (скажем, 2 раза нажали Remove, удалив 2объекта, потом нажали Edit, потом add)? Но это ведь очень муторно?

Извиняюсь за тупой вопрос, но правда не понимаю. В C++ это проще, мы там сами управляем свойствами объектов (ссылка, копия и пр)

Заранее спасибо за ответ
Re: Непонятки со ссылками на объекты в .NET
От: RushDevion Россия  
Дата: 21.02.19 12:38
Оценка: 1 (1) -1
В C# все переменные передаются по значению.
Для value-типов такая передача фактически означает копирование содержимого переменной.
Для reference-типов, также происходит копирование значения, но т.к. значение является (в терминах C++) указателем на объект,
то скопированная ссылка будет указывать на тот же самый объект.
А вариантов в тебя несколько:
Можно создавать копию списка перед передачей в диалог.
Можно сделать свойство IsDeleted для элементов списка. Тогда диалог просто выставляет это свойство и не показывает элементы с IsDeleted=true.
Re: Непонятки со ссылками на объекты в .NET
От: Ночной Смотрящий Россия  
Дата: 21.02.19 15:24
Оценка: 1 (1) -1
Здравствуйте, justStudent, Вы писали:

S>А по факту получается, что в objectsList уже этого объекта нет (он был удален в обработчике кнопки Remove). Как я понимаю, это из-за того, что объекты передаются по ссылке. Т.е. objectsList и dlg.objectsList указывают на один список. Как же быть в этом случае? Делаю копию списка (со всеми его элементами)?


Да, так проще всего.

S> Или хранить список операций и их атрибутов (скажем, 2 раза нажали Remove, удалив 2объекта, потом нажали Edit, потом add)? Но это ведь очень муторно?


Зато позволяет делать undo, т.е. многоуровневую отмену.

S>Извиняюсь за тупой вопрос, но правда не понимаю. В C++ это проще, мы там сами управляем свойствами объектов (ссылка, копия и пр)


В С++ ровно так же. Наличие ссылочной семантики от языка никак не зависит.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re: Непонятки со ссылками на объекты в .NET
От: MozgC США http://nightcoder.livejournal.com
Дата: 21.02.19 15:38
Оценка: 1 (1)
Используйте какой-нибудь список, который поддерживает отложенное сохранение, т.е. чтобы сначала можно было добавить или удалить элементы, а потом вызывать что-то типа AcceptChanges() или RejectChanges(). Что-то типа такого:
https://github.com/igor-tkachev/bltoolkit/blob/master/Source/EditableObjects/EditableList.cs
Re[2]: Непонятки со ссылками на объекты в .NET
От: justStudent  
Дата: 21.02.19 17:31
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Используйте какой-нибудь список, который поддерживает отложенное сохранение, т.е. чтобы сначала можно было добавить или удалить элементы, а потом вызывать что-то типа AcceptChanges() или RejectChanges(). Что-то типа такого:

MC>https://github.com/igor-tkachev/bltoolkit/blob/master/Source/EditableObjects/EditableList.cs
В итоге почти так и сделал. Диалогов у меня не много, пока отдельный класс под редактируемый список делать не стал. Обошелся небольшим хелпером:

public class EditablePair<T> where T : class
{
  public EditablePair(T original)
  {
    this.original = original;
    this.isDeleted = false;
    this.updated = null;
  }

  public T getResult()
  {
    if (updated != null)
      return updated;

    return original;
  }

  public T original { get; private set; }
  public bool isDeleted { get; set; }
  public T updated { get; set; }
}


Ну и в диалоге храню массив таких объектов, вместо оригинального. Плюс сделал конструкторы глубокого копирования для всех объектов.
Re[3]: Непонятки со ссылками на объекты в .NET
От: MozgC США http://nightcoder.livejournal.com
Дата: 21.02.19 19:22
Оценка: 1 (1) +1
Я не буду комментировать решение по дизайну обертки, но позволю себе несколько рекоммендаций по оформлению C# кода:
1) Публичные поля и свойства принято делать с большой буквы, как и все методы (публичные и приватные)
2) Тело метода GetResult() можно упростить: return updated ?? original; Начиная с C# 6 можно вообще написать так: public T GetResult() => updated ?? original;
3) this обычно не пишут, если это явно не помогает пониманию кода или разрешению конфликта имен.
4) Если ReSharper еще не стоит, то настоятельно рекомендую поставить, он очень сильно помогает.
Отредактировано 21.02.2019 21:31 MozgC . Предыдущая версия . Еще …
Отредактировано 21.02.2019 19:25 MozgC . Предыдущая версия .
Отредактировано 21.02.2019 19:23 MozgC . Предыдущая версия .
Re[4]: Непонятки со ссылками на объекты в .NET
От: justStudent  
Дата: 22.02.19 08:24
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Я не буду комментировать решение по дизайну обертки, но позволю себе несколько рекоммендаций по оформлению C# кода:

MC>1) Публичные поля и свойства принято делать с большой буквы, как и все методы (публичные и приватные)
MC>2) Тело метода GetResult() можно упростить: return updated ?? original; Начиная с C# 6 можно вообще написать так: public T GetResult() => updated ?? original;
MC>3) this обычно не пишут, если это явно не помогает пониманию кода или разрешению конфликта имен.
MC>4) Если ReSharper еще не стоит, то настоятельно рекомендую поставить, он очень сильно помогает.

Спасибо за ваши комментарии. Обязательно учту.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.