Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: Андрей Бушман от 16-05-2014, 11:59:19

Название: RegAppTableRecord & Dispose
Отправлено: Андрей Бушман от 16-05-2014, 11:59:19
Меня несколько смутила здесь (http://spiderinnet1.typepad.com/blog/2012/11/autocad-net-xdata-add-new-xdata-to-entityobject.html) инициализация объекта RegAppTableRecord в блоке using, с последующим его добавлением в базу данных чертежа. Т.е. по факту для добавленного объекта будет вызван Dispose, что несколько противоречит этому (http://bushman-andrey.blogspot.ru/2014/03/autocad-net-api-idisposable.html).
На моё замечание, автор пишет:
Цитировать
It might be true in the ARX/C++ world, but not for .NET. In fact, wrapping the RegAppTableRecord creation in a using block prevents AutoCAD from crashing if the object is not able to be successfully added to the database due to some reason. If successful, it won't hurt to dispose of the newly created RegAppTableRecord instance even if not quite necessary in this case.
Я не понял, каким образом в указанном случае блок using может предотвратить падение AutoCAD? Данный блок лишь гарантирует вызов RegAppTableRecord.Dispose, но не занимается обработкой исключений, как это делает try\catc. Если бы речь шла о try\catch, то это бы больше походило на правду, но using...

К примеру Волмслей здесь (http://through-the-interface.typepad.com/through_the_interface/2007/04/adding_xdata_to.html) не использует блок using для инициализации RegAppTableRecord, а так же не вызывает для него Dispose.

Я допускаю возможность, что автор ошибается, поэтому на всякий случай выношу мой вопрос сюда, дабы через А.Н. (долгих ему лет жизни) можно было бы уточнить этот момент непосредственно у Автодеска.
Название: Re: RegAppTableRecord & Dispose
Отправлено: Александр Ривилис от 16-05-2014, 13:36:45
Обойдемся без Autodesk:
1) Берем acdbmgd.dll и утилиту ILSpy.
2) Исследуем класс DBObject.
3) Находим его метод Dispose
4) Убеждаемся, что в конечном итоге он сводится к вызову DeleteUnmanagedObject
5) Анализируем DeleteUnmanagedObject:
Код - C# [Выбрать]
  1. protected unsafe override void DeleteUnmanagedObject()
  2. {
  3.         AcDbObject* impObj = this.GetImpObj();
  4.         AcDbObjectId acDbObjectId;
  5.         if (((*<Module>.AcDbObject.objectId(impObj, &acDbObjectId) == 0L) ? 1 : 0) != 0)
  6.         {
  7.                 if (impObj != null)
  8.                 {
  9.                         object arg_24_0 = calli(System.Void* modopt(System.Runtime.CompilerServices.CallConvCdecl)(System.IntPtr,System.UInt32), impObj, 1, *(*(long*)impObj));
  10.                 }
  11.         }
  12.         else
  13.         {
  14.                 int num = (int)<Module>.AcDbObject.close(this.GetImpObj());
  15.                 if (num != 0)
  16.                 {
  17.                         throw new Exception((ErrorStatus)num);
  18.                 }
  19.         }
  20. }
6) Убеждаемся, что если у объекта свойство ObjectId равно null, то идет освобождение памяти для неуправляемого объекта, вокруг которого наш объект лишь обертка, а если отлично от null, то вызывается метод Close этого же неуправляемого объекта.

Далее делаем выводы что в коде автора в случае нормального выполнения Close будет вызван дважды, что как раз и может приводить к краху AutoCAD.
Первый Close будет вызван при выходе из блока  using (RegAppTableRecord regAppRecord = new RegAppTableRecord()) {}
Второй Close будет вызван при вызове   tr.Commit();
Название: Re: RegAppTableRecord & Dispose
Отправлено: Андрей Бушман от 16-05-2014, 14:26:48
Далее делаем выводы что в коде автора в случае нормального выполнения Close будет вызван дважды, что ка раз и может приводить к краху AutoCAD.
Автор в своём коде не вызывает Close, поэтому дважды он, наверное, не будет выполнен, хотя... Когда транзакция закрывается, она вызывает Dispose или Close для объектов, добавленных ею в базу данных, или нет? Насколько я помню - вызывает Dispose...

P.S. Честно говоря, показанный выше код для меня не многим понятней китайской азбуки (строки 5 и 9):

Код - C# [Выбрать]
  1.  ? 1 : 0) != 0
Например, насколько я вижу - без этого можно было спокойно обойтись (похоже, что ILSpy "нагенерировал" от души)...
Название: Re: RegAppTableRecord & Dispose
Отправлено: Александр Ривилис от 16-05-2014, 15:51:38
Насколько я помню - вызывает Dispose...
Я же выше показал, что Dispose в свою очередь для наследников DBObject вызывает Close, если у них ObjectId != null.
А он не равен null, так как  regAppTable.Add(regAppRecord); устанавливает для него ненулевой ObjectId.
Например, насколько я вижу - без этого можно было спокойно обойтись (похоже, что ILSpy "нагенерировал" от души)...
Главное суть. Понятно, что оптимизацией кода он не занимается, а только выполняет дизассемблирование.
Название: Re: RegAppTableRecord & Dispose
Отправлено: Андрей Бушман от 16-05-2014, 15:56:34
Я это помню, но и вы ещё раз повнимательней прочтите то, что я написал:
Цитировать
Когда транзакция закрывается, она вызывает Dispose или Close для объектов, добавленных ею в базу данных, или нет? Насколько я помню - вызывает Dispose...
Ответ простой: либо да, либо нет. Предполагаю, что да (т.е. выполняется уничтожение объекта).
Название: Re: RegAppTableRecord & Dispose
Отправлено: Александр Ривилис от 16-05-2014, 15:59:08
Ответ простой: либо да, либо нет. Предполагаю, что да (т.е. выполняется уничтожение объекта).
Ох! Ничего он не уничтожает. Запомни, что метод Dispose не всегда уничтожает объект. Перечитай (внимательно) что я написал выше.
Название: Re: RegAppTableRecord & Dispose
Отправлено: Дима_ от 16-05-2014, 17:29:04
Ответ простой: либо да, либо нет. Предполагаю, что да (т.е. выполняется уничтожение объекта).
Оп оп - вызов Dispose() и уничтожение объекта- "это 4 разных человека" - любой объект и так уничтожит GC когда он будет "никому не нужен" - .Dispose() - это как-бы сообщения системе - "я освободил".
Название: Re: RegAppTableRecord & Dispose
Отправлено: Александр Ривилис от 16-05-2014, 18:53:38
Я немного подправил текст первого ответа (http://adn-cis.org/forum/index.php?topic=737.msg2742#msg2742).
Название: Re: RegAppTableRecord & Dispose
Отправлено: Андрей Бушман от 16-05-2014, 20:27:00
Я немного подправил текст первого ответа.

Цитата: Александр Ривилис
Первый Close будет вызван при выходе из блока  using (RegAppTableRecord regAppRecord = new RegAppTableRecord()) {}
Второй Close будет вызван при вызове   tr.Commit();
Вот об этом я и писал здесь (http://adn-cis.org/forum/index.php?topic=737.msg2744#msg2744).