Как правильно обмениваться переменными между методами?

Автор Тема: Как правильно обмениваться переменными между методами?  (Прочитано 15701 раз)

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

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн Максим МаркевичАвтор темы

  • ADN Club
  • ****
  • Сообщений: 254
  • Карма: 29
  • Skype: evthisrel
Всем привет. Нужна помощь и совет.
Раньше я писал свой программный код в один метод и бед не знал. ;)
Но, когда кода становится слишком много, править/дописывать что-то в данный метод становится настолько сложно, что я решил навести порядки во всем, что написано, пока не стало поздно.
Так вот, вопрос по поводу обмена переменными между методами, суть:
Иногда, когда несколько методов используют одни и те же переменные, я делаю так (объявляю их в классе):
Код - C# [Выбрать]
  1. namespace Namespace
  2. {
  3.     public static class Class
  4.     {
  5.         public static List<string> listTest = new List<string>();
  6.  
  7.         // Первый метод
  8.         private static void voidTest1()
  9.         {
  10.             listTest.Add("Что-то добавляем");
  11.         }
  12.  
  13.         // Второй метод (командный)
  14.         [CommandMethod("Command")]
  15.         public static void voidTest2()
  16.         {
  17.             voidTest1();
  18.             listTest.Add("Что-то добавляем");
  19.         }
  20.     }
  21. }
Но, если командный метод voidTest2 вызывается несколько раз в AutoCAD, то, понятно дело, переменная listTest будет дописываться и дописываться (то есть список будет дополняться, так как является переменной класса), что не всегда удобно. Иногда приходится ее "обнулять" в конце 2го метода.
Можно было бы, переменную listTest декларировать в первом методе, а оттуда получать во втором. Делаю это примерно вот так:
Код - C# [Выбрать]
  1. namespace Namespace
  2. {
  3.     public static class Class
  4.     {
  5.         // Первый метод
  6.         private static void voidTest1(out List<string> listTestout)
  7.         {
  8.             var listTest = new List<string>();
  9.             listTest.Add("Что-то добавляем");
  10.             listTestout = listTest;
  11.         }
  12.  
  13.         // Тут надо декларировать что-то типа поле, чтобы передать переменную
  14.         public static List<string> listTestFromVoidTest1;
  15.  
  16.         // Второй метод (командный)
  17.         [CommandMethod("Command")]
  18.         public static void voidTest2()
  19.         {
  20.             voidTest1(out listTestFromVoidTest1);
  21.             listTestFromVoidTest1.Add("Что-то добавляем");
  22.         }
  23.     }
  24. }
Но, если переменных много, то тоже это становится очень неудобно. И я снова задумываюсь о том, что, может, зря я отказался от одного всеобъемлющего метода.  ???

Вот, таким образом, на текущий момент я выделил для себя 2 вышеописанных способа. Поправьте, пожалуйста, если я что-то неправильно понимаю.
P.S. Примеры придумывал исключительно для пояснения двух своих методов. Особого смысла в них искать не стоит.
Заранее, спасибо за помощь!

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Думаю что многое если не всё зависит от самих данных и от того, что с ними следует делать.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Максим МаркевичАвтор темы

  • ADN Club
  • ****
  • Сообщений: 254
  • Карма: 29
  • Skype: evthisrel
Думаю что многое если не всё зависит от самих данных и от того, что с ними следует делать.
Хорошо, тогда я конкретизирую задачу.
Я пишу тут плагинчик, который вставляет в чертеж сразу 2 таблицы: таблица №1 формируется на основании данных, считанных с блоков, а вот таблица №2 формируется на основании таблицы №1.
Упрощенная концепция кода выглядит примерно так:
Код - C# [Выбрать]
  1. namespace Tables
  2. {
  3.     public static class SpecificationAndStateOfSteel
  4.     {
  5.         // Создание таблицы спецификации
  6.         private static void CreateSpecification(Point3d pt, out Table tableOut)
  7.         {
  8.             // Здесь происходит создание таблицы table1, все дела
  9.             tableOut = table1;
  10.         }
  11.  
  12.         // Создание ВРС
  13.         private static void CreatingStateOfSteel(Table soureTable, Point3d pt)
  14.         {
  15.             // Здесь происходит создание таблицы table2, все дела
  16.         }
  17.  
  18.         private static Table table1out;
  19.  
  20.         [CommandMethod("SPSOS")]
  21.         public static void InsertTables()
  22.         {
  23.             var doc = AppServCore.Application.DocumentManager.MdiActiveDocument;
  24.             if (doc == null)
  25.                 return;
  26.             var db = doc.Database;
  27.             var ed = doc.Editor;
  28.             var pr = ed.GetPoint("\nУкажите точку вставки таблиц: ") as PromptPointResult;
  29.             if (pr.Status == PromptStatus.OK)
  30.             {
  31.                 CreateSpecification(pr.Value, out table1out);
  32.                 CreatingStateOfSteel(table1out, pr.Value);
  33.             }
  34.         }
  35.     }
  36. }
Проблема в том, что после вставки таблица №1 становится нередактируемой (см. скринкаст), то есть редактируемой, но после того, как закрыть-открыть чертеж. Похожая ситуация на "когда не закоммитил транзакцию". Так вот, у меня создается впечатление, что это именно из-за использования out параметра в методе создания таблицы №1.


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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Ну ты даёшь. Это совсем не имеет отношения к данной теме.  При закрытии транзакции все открытые, а так же созданные и добавленные в базу объекты базы (наследники DBObject, т.е в том числе и Table) становятся недействительными. Т.е. твой table1out действителен только внутри транзакции. Поэтому для того, для чего ты хочешь её использовать, следует хранить не саму таблицу (Table), а её ObjectId, и при необходимости его открывать.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Максим МаркевичАвтор темы

  • ADN Club
  • ****
  • Сообщений: 254
  • Карма: 29
  • Skype: evthisrel
При закрытии транзакции все открытые, а так же созданные и добавленные в базу объекты базы (наследники DBObject, т.е в том числе и Table) становятся недействительными. Т.е. твой table1out действителен только внутри транзакции.
Извиняюсь. Просто однажды словил ошибку и, как уже сейчас понял, неправильно ее интерпретировал.
Ну ты даёшь. Это совсем не имеет отношения к данной теме.
Александр Наумович, Ну как это не имеет?? Я вижу самую прямую связь!!
По сути, спросил изначально, как обмениваться переменными между методами, а потом вопрос, как корректно передать таблицу из метода в метод?
Разве это не схожие вещи?
Ведь вопрос, в первую очередь в том, корректно ли я делаю вот здесь:
Упрощенная концепция кода выглядит примерно так:
У меня не выходило, я подумал, что неправильно передаю таблицу между методами!
Вот и высказал свои мысли бестолковые как оказалось. Но что в этом страшного? Я несколько дней разбирался прежде, чем тему создать!



Оффлайн Максим МаркевичАвтор темы

  • ADN Club
  • ****
  • Сообщений: 254
  • Карма: 29
  • Skype: evthisrel
Поэтому для того, для чего ты хочешь её использовать, следует хранить не саму таблицу (Table), а её ObjectId, и при необходимости его открывать.
У меня, кстати, получилось сохранить саму таблицу.
Прикрепляю пример кода, который создает 2 таблицы: в 1-ю значения записываются вручную, а во 2-й значения берутся из первой и модифицируются.
Извините, вам запрещён просмотр содержимого спойлеров.

Скринкаст работы кода:


В посте о нередактируемой таблице проблема была не в передаче самой таблицы, а в том, что я 2 раза вызывал метод - создание табличного стиля - и не проверял, существует ли такой. Поэтому получался такой типа глюк.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
У меня, кстати, получилось сохранить саму таблицу.
Еще раз. После завершения транзакции объект участвующий в транзакции недействителен. Вплоть до Fatal Error при обращении к нему. Тебе просто крупно повезло. В других условиях или на другой версии AutoCAD/другом PC и т.д. не повезет. Крайне не рекомендую так делать.
Разве это не схожие вещи?
То что разрешено для string не разрешено для Table. Поэтому я был совершенно прав, говоря что многое зависит от самих данных.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Максим МаркевичАвтор темы

  • ADN Club
  • ****
  • Сообщений: 254
  • Карма: 29
  • Skype: evthisrel
Еще раз. После завершения транзакции объект участвующий в транзакции недействителен. Вплоть до Fatal Error при обращении к нему. Тебе просто крупно повезло. В других условиях или на другой версии AutoCAD/другом PC и т.д. не повезет. Крайне не рекомендую так делать.
Крайне прислушиваюсь к Вашему совету.
Извините, вам запрещён просмотр содержимого спойлеров.

То что разрешено для string не разрешено для Table. Поэтому я был совершенно прав, говоря что многое зависит от самих данных.
Все как обычно. Всегда Ваш первый ответ, даже если сразу не кажется решением темы, то спустя "подумал" уже кажется.
Вышло все банально, насчет таблиц. Блин, я вот приходил уже к пониманию этого, но прошло время, рутинная работа как-то поела это понимание, забылось. А раз забылось, значит и не понимал до конца. Теперь мне легче. Спасибо Вам!

Отмечено как Решение Максим Маркевич 02-10-2016, 22:50:58

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Раньше я писал свой программный код в один метод и бед не знал.
Но, когда кода становится слишком много, править/дописывать что-то в данный метод становится настолько сложно, что я решил навести порядки во всем, что написано, пока не стало поздно.
Так вот, вопрос по поводу обмена переменными между методами, суть:
Иногда, когда несколько методов используют одни и те же переменные, я делаю так (объявляю их в классе):
Ну если Вы решили навести порядок - то я бы Вам рекомендовал по возможности избавится от методов которые используют внешние переменные - есть аргументы - есть возвращаемое значение - ими и оперируйте.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Ну если Вы решили навести порядок - то я бы Вам рекомендовал по возможности избавится от методов которые используют внешние переменные - есть аргументы - есть возвращаемое значение - ими и оперируйте.
Тем более, что в данном случае это всего лишь ObjectId таблицы.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
Раньше я писал свой программный код в один метод и бед не знал. ;)
Но, когда кода становится слишком много, править/дописывать что-то в данный метод становится настолько сложно, что я решил навести порядки во всем, что написано, пока не стало поздно.
Изобретение велосипедов дело интересное но малоэффективное.
Эти вопросы возникают у каждого программиста, и они уже были систематизированы, обдуманы, выработаны методы решения.
Решение твоих проблем в книгах "Чистый код" или "Совершенный код".

Чисто на вскидку, что бы я сделал:

1. CreateTable1(pr.Value);
CreateTable2(pr.Value);
быстро просматривая твой код, возможно стоит избежать дублирования и вынести один единственный метод CreateTable,
который всегда принимает Point3d и доп параметры, тут стоит определиться что он будет принимать.
Например CreateTable(Point3d insertPoint, string str1, string str2),
Возможно CreateTable(Point3d insertPoint, string[] str),
Или так CreateTable(Point3d insertPoint, ObjectId tableId),

2. Перепиши InsertTables к примеру так:
var insertPoint = GetPoint();
if  (insertPoint!=null)
{
   ObjectId tableId = CreateTable(insertPoint, ObjectId.Null);
   CreateTable(insertPoint, tableId );
}
Т.е. запрос точки вынеси в отдельный метод GetPoint() так удобнее читать сам метод InsertTables.
проверка точки так не выйдет, это всего лишь схема изменения, додумай сам до конца.

3. InsertTables вынеси первым методом в классе,
потом GetPoint(), затем CreateTable().
т.е. стартовую функцию класса ставь вначале, затем расположи в порядке обращения к методам чисто читать удобнее.

Что касается темы "Как правильно обмениваться переменными между методами?"
тут много вариантов, нужно продумать программу, учитывать ее размер и что будет в ней меняться. Сколько классов создавать 1 или десяток.
Если переменные хранятся в одном месте и тебе заранее неизвестны, например параметры таблицы, например ты не знаешь будет ли цвет когда либо или нет.
то можешь создать класс TablePropertyes туда сразу добавить точку вставки и передавать его в метод построения CreateTable(TablePropertyes) так ты получишь параметры, которые сможешь дополнять независимо от основной логики программы, и дополнять CreateTable в зависимости от доступных параметров.

Оффлайн Максим МаркевичАвтор темы

  • ADN Club
  • ****
  • Сообщений: 254
  • Карма: 29
  • Skype: evthisrel
Ну если Вы решили навести порядок - то я бы Вам рекомендовал по возможности избавится от методов которые используют внешние переменные - есть аргументы - есть возвращаемое значение - ими и оперируйте.
Я так и сделал уже. С таблицами иначе и не выходит. А вот работать со списками и декларировать их в классе крайне неудобно. Спасибо за совет, который укрепил веру в правильный выбор. Очень ценю.
Тем более, что в данном случае это всего лишь ObjectId таблицы.
И еще в шапке темы вопрос касался списков, точнее пример был со списками.
Конкретно, в коде, что я пишу, есть метод который считывает инфу с блоков, он создает около 10 списков, затем я их использую в методе создание спецификации, а потом с самой спецификацией и списками с метода, который считывает инфу с блоков, работаю в методе создание ведомости расхода стали. В общем, много возвращаемых значений), но, в принципе, ничего страшного, пережить это можно. Я лишь хотел убедиться, что то, к чему пришел, правильно, дабы не делать "плохого", или как там в простонародье называют :), кода. А, так как пришел я к двум вариантам, то и хотел спросить, как лучше. Да и, вообще, много всего я понял за последние пару дней. Спасибо за терпение и извините за некоторые нелепости.
Изобретение велосипедов дело интересное но малоэффективное.
Эти вопросы возникают у каждого программиста, и они уже были систематизированы, обдуманы, выработаны методы решения.
Решение твоих проблем в книгах "Чистый код" или "Совершенный код".
Спасибо. Обязательно просмотрю. Просто, как правило, форум эффективней с позиции трудозатрат. Здесь получаешь конкретные ответы от опытных товарищей, делаешь выбор и дальше с этим работаешь.
1. CreateTable1(pr.Value);
CreateTable2(pr.Value);
быстро просматривая твой код, возможно стоит избежать дублирования и вынести один единственный метод CreateTable,
который всегда принимает Point3d и доп параметры, тут стоит определиться что он будет принимать.
Например CreateTable(Point3d insertPoint, string str1, string str2),
Возможно CreateTable(Point3d insertPoint, string[] str),
Или так CreateTable(Point3d insertPoint, ObjectId tableId),
Забавно, но у меня в коде так и сделано. :)
Сразу идет метод:
Код - C# [Выбрать]
  1. GetInformationFromBlocks(out List<string> list0, out List<string> list1...)
который мне выдает около 10 списков.
Далее я их использую в создании первой таблицы, также есть аргумент точки вставки и возвращаемое значение Id таблицы:
Код - C# [Выбрать]
  1. CreateSpecification(Point3d pt, List<string> list0, List<string> list1..., out ObjectId tableId)
Далее создается вторая таблица:
Код - C# [Выбрать]
  1. CreatingStateOfSteel(Point3d pt, ObjectId tableId)
Я не могу их объединить в один метод, потому как механизмы создания ну очень разные.
Ну и далее идет метод вставки таблиц:
Код - C# [Выбрать]
  1. InsertTables()
в котором совсем все просто и понятно.
В общем, есть еще методы типа создание табличного стиля, настройка стиля.
Это то, что я получил после модернизации своего одного метода. Ушло много времени на разобраться, но как же сейчас все круто!! :) Я счастлив просто!
Теперь я без проблем могу дописать вставку еще какой таблицы, вставить только одну, изменить табличный стиль или его настройки. Все теперь по-человечески.
Несколько дней проклинал идею улучшить код, зато теперь доволен как слон.
2. Перепиши InsertTables к примеру так:
var insertPoint = GetPoint();
if  (insertPoint!=null)
{
   ObjectId tableId = CreateTable(insertPoint, ObjectId.Null);
   CreateTable(insertPoint, tableId );
}
Т.е. запрос точки вынеси в отдельный метод GetPoint() так удобнее читать сам метод InsertTables.
проверка точки так не выйдет, это всего лишь схема изменения, додумай сам до конца.
Идею понял! Забавно! Обязательно поэкспериментирую!
3. InsertTables вынеси первым методом в классе,
потом GetPoint(), затем CreateTable().
т.е. стартовую функцию класса ставь вначале, затем расположи в порядке обращения к методам чисто читать удобнее.
Понял. А реально, ведь удобней! Спасибо! Очевидные вещи, конечно. Но, пока сам дойдешь.. Спасибо за ценные советы!
Если переменные хранятся в одном месте и тебе заранее неизвестны, например параметры таблицы, например ты не знаешь будет ли цвет когда либо или нет.
то можешь создать класс TablePropertyes туда сразу добавить точку вставки и передавать его в метод построения CreateTable(TablePropertyes) так ты получишь параметры, которые сможешь дополнять независимо от основной логики программы, и дополнять CreateTable в зависимости от доступных параметров.
Как же все вариативно и интересно!! Здорово.

Александр Ривилис, Дима_, Привалов Дмитрий, Вы, конечно, извините за такие вопросы по созданию велосипедов. Я не так давно занимаюсь этим всем. И просто с открытым ртом все это читаю. В какой-то момент, когда уже написано много плагинчиков, когда число строк становится очень большим (у меня так получается, что практика несколько опережает теорию, конечно, таким образом много спотыкаешься, но зато результаты первые есть быстрее, чем в противном случае), я начал понимать, что программирую на языке орков. И для того, чтобы дальше с этим работать мне нужна структура и система. Собственно, лично мне всегда проще спросить на форуме, чем читать книжки. Так выходит эффективней. Тем более, здесь плохого не посоветуют. Единственное, это не должно оцениваться как неуважение к форумчанам и нежелание читать книги. Темы стараюсь создавать только после самостоятельного изучения (продолжительного по времени). Собственно в шапке я и написал о том, что делаю так и этак. Спросил, как лучше? А не то, чтобы просто спросил, как делать. То есть стараюсь разобраться сам. Просто порой нужно авторитетное мнение в связи с неопытностью и желанием делать быстро и правильно. Спасибо большое Вам за ответы и советы!

PS. Решением темы отмечаю пост, который дал ответ на мой вопрос и в соответствии с советом которого планирую дальше работать.

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Конкретно, в коде, что я пишу, есть метод который считывает инфу с блоков, он создает около 10 списков, затем я их использую в методе создание спецификации, а потом с самой спецификацией и списками с метода, который считывает инфу с блоков, работаю в методе создание ведомости расхода стали. В общем, много возвращаемых значений), но, в принципе, ничего страшного, пережить это можно.
Мне хорошо знакомо о том что Вы пишете. У меня еще помимо ведомостей, и оптимизация раскроя и чертежи КМД, и задание на ЧПУ распиловки и фрезеровки, и учет и обработка полезных остатков и пр. Мой Вам совет - ни в коем случае не привязывайте Ваши ведомости к блокам (имеется в виду на логическом уровне). Что там за инфа с блоков на 10 списков? У меня, например, всей инфы - имя блока и далее список параметр(или атрибут) - значение. Создайте структуры (классы - что Вам ближе) которые всесторонне будут описывать ваш конечный продукт, а как и из чего получать результат это вопрос второй. Вполне возможно, вскоре это будут не только блоки из автокада, а например еще и проводки из 1С, и формат выходных таблиц будет совсем другим и не только для "человеческого" прочтения. И если вернуться к заголовку темы - общих переменных в коде при всем этом у меня нет ни одной, не для того чтоб Вас в чем-то убедить - просто вот не понадобились.

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 624
  • Карма: 158
    • ПГСу Бложик
Мой Вам совет - ни в коем случае не привязывайте Ваши ведомости к блокам (имеется в виду на логическом уровне). Что там за инфа с блоков на 10 списков? У меня, например, всей инфы - имя блока и далее список параметр(или атрибут) - значение. Создайте структуры (классы - что Вам ближе) которые всесторонне будут описывать ваш конечный продукт, а как и из чего получать результат это вопрос второй.
ИМХО, очень правильный совет! Гуглить MVC

Оффлайн Максим МаркевичАвтор темы

  • ADN Club
  • ****
  • Сообщений: 254
  • Карма: 29
  • Skype: evthisrel
Мой Вам совет - ни в коем случае не привязывайте Ваши ведомости к блокам (имеется в виду на логическом уровне).
Так, я совсем не понял, что значит не привязываться на логическом уровне?
Что там за инфа с блоков на 10 списков?
Это списки типа диаметр, класс арматуры, длина и прочее
Вот, записал примерный механизм работы:
Создайте структуры (классы - что Вам ближе) которые всесторонне будут описывать ваш конечный продукт
Да, но для этого мне нужна входная информация в виде списков, иначе конечный продукт будет пустым. Или я что-то не так понимаю?
И если вернуться к заголовку темы - общих переменных в коде при всем этом у меня нет ни одной, не для того чтоб Вас в чем-то убедить - просто вот не понадобились.
Я прекрасно понимаю, что такое "еще помимо ведомостей, и оптимизация раскроя и чертежи КМД, и задание на ЧПУ распиловки и фрезеровки, и учет и обработка полезных остатков и пр." и не понимаю, как тогда это реализовано? Откуда берется инфа о металле? Где все это хранится? Как пользователь изменяет что-то?