RegAppTableRecord & Dispose

Автор Тема: RegAppTableRecord & Dispose  (Прочитано 5528 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
RegAppTableRecord & Dispose
« : 16-05-2014, 11:59:19 »
Меня несколько смутила здесь инициализация объекта RegAppTableRecord в блоке using, с последующим его добавлением в базу данных чертежа. Т.е. по факту для добавленного объекта будет вызван Dispose, что несколько противоречит этому.
На моё замечание, автор пишет:
Цитировать
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...

К примеру Волмслей здесь не использует блок using для инициализации RegAppTableRecord, а так же не вызывает для него Dispose.

Я допускаю возможность, что автор ошибается, поэтому на всякий случай выношу мой вопрос сюда, дабы через А.Н. (долгих ему лет жизни) можно было бы уточнить этот момент непосредственно у Автодеска.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: RegAppTableRecord & Dispose
« Ответ #1 : 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();
« Последнее редактирование: 16-05-2014, 18:11:42 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: RegAppTableRecord & Dispose
« Ответ #2 : 16-05-2014, 14:26:48 »
Далее делаем выводы что в коде автора в случае нормального выполнения Close будет вызван дважды, что ка раз и может приводить к краху AutoCAD.
Автор в своём коде не вызывает Close, поэтому дважды он, наверное, не будет выполнен, хотя... Когда транзакция закрывается, она вызывает Dispose или Close для объектов, добавленных ею в базу данных, или нет? Насколько я помню - вызывает Dispose...

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

Код - C# [Выбрать]
  1.  ? 1 : 0) != 0
Например, насколько я вижу - без этого можно было спокойно обойтись (похоже, что ILSpy "нагенерировал" от души)...
« Последнее редактирование: 16-05-2014, 14:53:00 от Андрей Бушман »

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: RegAppTableRecord & Dispose
« Ответ #3 : 16-05-2014, 15:51:38 »
Насколько я помню - вызывает Dispose...
Я же выше показал, что Dispose в свою очередь для наследников DBObject вызывает Close, если у них ObjectId != null.
А он не равен null, так как  regAppTable.Add(regAppRecord); устанавливает для него ненулевой ObjectId.
Например, насколько я вижу - без этого можно было спокойно обойтись (похоже, что ILSpy "нагенерировал" от души)...
Главное суть. Понятно, что оптимизацией кода он не занимается, а только выполняет дизассемблирование.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: RegAppTableRecord & Dispose
« Ответ #4 : 16-05-2014, 15:56:34 »
Я это помню, но и вы ещё раз повнимательней прочтите то, что я написал:
Цитировать
Когда транзакция закрывается, она вызывает Dispose или Close для объектов, добавленных ею в базу данных, или нет? Насколько я помню - вызывает Dispose...
Ответ простой: либо да, либо нет. Предполагаю, что да (т.е. выполняется уничтожение объекта).

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: RegAppTableRecord & Dispose
« Ответ #5 : 16-05-2014, 15:59:08 »
Ответ простой: либо да, либо нет. Предполагаю, что да (т.е. выполняется уничтожение объекта).
Ох! Ничего он не уничтожает. Запомни, что метод Dispose не всегда уничтожает объект. Перечитай (внимательно) что я написал выше.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Re: RegAppTableRecord & Dispose
« Ответ #6 : 16-05-2014, 17:29:04 »
Ответ простой: либо да, либо нет. Предполагаю, что да (т.е. выполняется уничтожение объекта).
Оп оп - вызов Dispose() и уничтожение объекта- "это 4 разных человека" - любой объект и так уничтожит GC когда он будет "никому не нужен" - .Dispose() - это как-бы сообщения системе - "я освободил".

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: RegAppTableRecord & Dispose
« Ответ #7 : 16-05-2014, 18:53:38 »
Я немного подправил текст первого ответа.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: RegAppTableRecord & Dispose
« Ответ #8 : 16-05-2014, 20:27:00 »
Я немного подправил текст первого ответа.

Цитата: Александр Ривилис
Первый Close будет вызван при выходе из блока  using (RegAppTableRecord regAppRecord = new RegAppTableRecord()) {}
Второй Close будет вызван при вызове   tr.Commit();
Вот об этом я и писал здесь.