Открывать все подряд объекты на запись - плохая практика. Если есть сомнения, что объект надо будет редактировать, то открывайте на чтение. А прямо перед модификацией вызывайте UpgradeOpenВсё так, кроме того, что вместо UpgradeOpen нужно снова вызвать повторно Transaction.GetObject(...), но с OpenMode.ForWrite. UpgradeOpen - это для Open/Close (или OpenCloseTransaction) и может конфликтовать с обычной транзакцией.
моджет конфликтовать с обычной транзакциейДа что вы?! Точно? Я всегда так делаю и в куче примеров видел и у объекта IsWriteEnabled становится true... Неужели я столько лет косячил... шок...
Ты был не один. И я тоже такие примеры приводил с использованием UpgradeOpen. Но один старший товарищ (Art Cooney - один из руководителей разработки AutoCAD) объяснил мне, что я не прав. Это вылезло в одном из обновлений AutoCAD 2018. Тут подробности: https://forums.autodesk.com/t5/net/api-bug-2018-1-causes-crash-using-upgradeopen-on-dependent/m-p/7272262/highlight/true#M54471моджет конфликтовать с обычной транзакциейДа что вы?! Точно? Я всегда так делаю и в куче примеров видел и у объекта IsWriteEnabled становится true... Неужели я столько лет косячил... шок...
т е или заменить обычную транзакция на openclosetransaction или еще раз получать объект для записи?Менять ничего не надо. Просто вместо UpgradeOpen вызываешь снова myTransaction.GetObject, но уже с OpenMode.ForWrite.
а как же вот с оф сайта пример?Он ошибочен. И по той ссылке, которую я дал выше, это обсуждается.
https://knowledge.autodesk.com/search-result/caas/CloudHelp/cloudhelp/2015/ENU/AutoCAD-NET/files/GUID-CC5CC229-B122-4897-A8DA-5C5ADADB0F38-htm.html?_ga=2.51307242.2126543432.1539105496-1602586928.1535484681
а openclosetransaction чем хуже?Ничем не хуже. Он просто другой и требует большей внимательности от программиста.
или вначале предложенный способ проверки типа объекта не открывая его?В данном случае это вообще идеальный вариант, если пишешь под AutoCAD не старее 2009-го. В AutoCAD 2008 такого метода не было.
Он ошибочен. И по той ссылке, которую я дал выше, это обсуждается.Вот же ж.. Только что перелопатил весь код, убирал TopTransaction, а на завтра опять тотальный рефакторинг - убирать UpgradeOpen...
а с toptransaction что?А я внезапно понял, что toptransaction - это вовсе не обязательно МОЯ последняя транзакция. Мы ж в многопоточной среде! И регулярные сбои Автокада на диспозе объектов запросто могут быть из-за путаницы в транзакциях. Экономил на копейках (лишние параметры у методов не красивыми считал, раз тарнзакцию можно вроде как и не передавать), а проиграл сурово: переписывал горы кода - где транзакция длинная - заводил отдельную, где мелочевка - передаю теперь свыше в параметрах или полях классов.
if (objId.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(MText))))а есть ли разница между IsDerivedFrom, Equals и, например, == в данном случае?
{
MText mt = myTransaction.GetObject(objId, OpenMode.ForWrite) as MText;
//и далее какой-то код
}
а есть ли разница между IsDerivedFrom, Equals и, например, == в данном случае?IsDerivedFrom - это сам класс (в данном случае MText) и его наследники. В самом AutoCAD наследников для MText нет, но теоретически можно создать Custom Entity унаследованный от AcDbMText и для него создать .NET-обертку - наследник от MText (с именем например MyMText). Ну и тогда возникнет вопрос - обрабатывать только MText или MyMText тоже. Равенство вернет только MText, а IsDerivedFrom - оба класса.
IsDerivedFrom, Equals и, например, ==
последние два одинаковы? или есть разница в их работе?Надо смотреть внутрь класса RXClass. Но я бы наверное (для точного сравнения) сравнивал бы на равенство строки objId.ObjectClass.Name и RXObject.GetClass(typeof(MText)).NameIsDerivedFrom, Equals и, например, ==
Вот же ж.. Только что перелопатил весь код, убирал TopTransaction, а на завтра опять тотальный рефакторинг - убирать UpgradeOpen...На очереди ещё один рефакторинг - отказ от транзакций в пользу ObjectId.Open 8)
На очереди ещё один рефакторинг - отказ от транзакций в пользу ObjectId.Open 8)В ForRead - однозначно. А вот с ForWrite я бы сначала потестировал. Насколько я помню транзакции (я про обычные) для ForWrite лучше (быстрее).
отказ от транзакций в пользу ObjectId.OpenНи-ни. Моя СУБДшная натура категорически против отказа от транзакций, там где они возможны. А слухи, про их тормознутость сильно преувеличены. Я проверял. :)
Моя СУБДшная натура категорически против отказа от транзакций, там где они возможны.Я так понимаю, что это не те транзакции, что в СУБД. Общее у них только название. А по факту, получился инструмент, который на начальных этапах освоения API сильно упрощает жизнь, а в дальнейшем - может её сильно испортить.
где транзакция длинная - заводил отдельную, где мелочевка - передаю теперь свыше в параметрах или полях классов.В том-то и дело. Я так понимаю, что есть некоторые вспомогательные методы, которые выполняют обработку переданных данных. Пока они вызываются из командных методов, всё работает вроде как надо. Но впоследствии эти же методы возможно понадобится вызывать из различных событий, из методов Overrule и тд и тп, то есть, в тех случаях, когда транзакция может испортить работу AutoCAD, приводя к Fatal Error. Отлавливание таких ошибок - очень непростое дело.
это не те транзакции, что в СУБДПочему же не те - принцип как раз тот: изоляция изменений до коммита транзакции, откат всех изменений целиком. На ранних этапах (да и теперь) они конечно сильно УСЛОЖНЯЮТ жизнь, удлиняют код. В сравнении со всякими VBA. Но повышают дуракоустойчивость кода. В обработчиках событий транзакции у меня живут прекрасно и им там самое место. ИМХО. Нельзя сказать наверняка, но похоже больше фаталов от смешивания подходов - часть методов безтранзакционные, часть используют toptransaction не явно и влетают на чужие транзакции, которые внезапно комитятся, а открытые объекты остаются в вашем коде... и гуд-бай Автокад... API позволяет намешать такой винегрет, что мама не горюй. А примеры, понадерганные из форумов, этому только способствуют. И, как тут только что выяснилось, примеры с принципиальными ошибками пишут даже гуру.
Казалось бы, никакой проблемы - используем транзакцию и радуемся. Но! При обработке больших чертежей, в какой-то случайный момент вываливается исключение System.AccessViolationException без указания места, в котором это исключение возникло. Без транзакции исключений не возникаетЕсли поискать по форуму, можно найти ещё несколько тем, где обсуждается необходимость отказа от транзакций в определённых случаях.
Не верю!Ну ок. Я поделился своим опытом. Перенимать его или нет - дело хозяйское. ;)
Попробуйте использовать вот этот код:Проблема!
Код - C# [Выбрать]
if (objId.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(MText))))
Проблема!Кто куда залазит???
внешняя ссылка для него это блок и он залазит в нее (если я ищу блоки).
Проблема!Почему проблема? Внешняя ссылка и есть блок, внутри автокада очень многое можно привести к блоку (таблицы, размеры, выноски и т.д.).
внешняя ссылка для него это блок и он залазит в нее (если я ищу блоки).
Если Вам не нужны XRef, то и фильтруйте их: BlockTableRecord.IsFromExternalReferenceт е для проверки придется открыть блок через транзакцию и дополнительно получать так же через транзакцию BlockTableRecord полученного блока?
Угу.Если Вам не нужны XRef, то и фильтруйте их: BlockTableRecord.IsFromExternalReferenceт е для проверки придется открыть блок через транзакцию и дополнительно получать так же через транзакцию BlockTableRecord полученного блока?
т е для проверки придется открыть блок через транзакцию и дополнительно получать так же через транзакцию BlockTableRecord полученного блока?Можно и так, но ИМХО, проще написать метод расширения для ObjectId и проверять сразу в условии.
PS.Всё-таки слегка "пну" по поводу Close и Dispose. Если !ObjectId.IsNull (а это наш случай), то Dispose вызывает Close. Так что вызывать и Close и Dispose не следует. Если ObjectId.IsNull то Close вызвать нельзя.
За код, особо сильно не пинайте, "чукча не писатель, чукча читатель"