Как правильно выйти из процедуры?
От: Mono.m Россия  
Дата: 20.01.07 12:48
Оценка:
Коллеги, посоветуйте как в данном случае правильно выйти из процедуры.

Т.е. если cancel = true — отменяем всё нафик.

(сорри за табуляцию — установил последний sp, shift+tab перестал работать)
            cancel = false;
            try
            {
                SetStatus(barStaticItem1, "Соединение с сервером…");
                HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://microsoft.com");
                if (cancel) { req.Abort(); return; }
                req.BeginGetResponse(
                    delegate(IAsyncResult iar)
                    {
                        using (HttpWebResponse resp = (HttpWebResponse)req.EndGetResponse(iar))
                        {
                            // нужно ли использовать resp.Close()? или объект resp закроется автоматически, т.к. внутри Using?
                            if (cancel) { req.Abort(); resp.Close(); return; }
                            //
                            using (Stream sr = resp.GetResponseStream())
                            {
                                if (cancel) { req.Abort(); resp.Close(); sr.Close(); return; }
                                byte[] buff = new byte[4096];
                                int read = 1;
                                int size = 0;

                                using (MemoryStream data = new MemoryStream())
                                {
                                    while (read > 0)
                                    {
                                        // Вот тут проблема: несмотря на break() процедура SetStatus(barStaticItem1, "Загрузка…") всё-равно вызывается :-(
                                        if (cancel) { break; }
                                        read = sr.Read(buff, 0, buff.Length);
                                        data.Write(buff, 0, read);
                                        size += read;
                                        SetStatus(barStaticItem1, "Загрузка…");
                                        SetStatus(barStaticItem2, string.Format("{0} K", size / 1024));
                                    }
                                    if (cancel) {req.Abort(); resp.Close(); sr.Close(); data.Close(); return; }
                                    SetStatus(barStaticItem1, "Готово");
                                    Parse(Encoding.Default.GetString(data.ToArray()));
                                }
                            }
                        }
                    }, null);
            }
            catch (WebException ex)
            {
                MessageBox.Show(ex.Message);
            }


Заранее спасибо за ответ.
Re: Как правильно выйти из процедуры?
От: kostya.misura  
Дата: 20.01.07 15:59
Оценка:
Здравствуйте, Mono.m, Вы писали:

MM> нужно ли использовать resp.Close()? или объект resp закроется автоматически, т.к. внутри Using?

Для меня это до сих пор нерешенный вопрос. Лично, я тихонечко не люблю классы которые реализуют IDisposable и при этом предоставляют методы типа public Close. В каждом конеретном случае я лезу рефлектором, что бы удостоверится что Dispose вызывает этот метод. В Вашем случае это так:
void IDisposable.Dispose()
{
      try
      {
            this.Close();
            this.OnDispose();
      }
      catch
      {
      }
}

Так что можно забыть про метод Close и спокойно использовать using

MM> // Вот тут проблема: несмотря на break() процедура SetStatus(barStaticItem1, "Загрузка…") всё-равно вызывается :-(
MM> if (cancel) { break; }

А где именно cancel устанавливается в true? Т.к в примере я этого не увидел. Может я пропустил?
Re[2]: Как правильно выйти из процедуры?
От: Mono.m Россия  
Дата: 20.01.07 19:55
Оценка:
Здравствуйте, kostya.misura, Вы писали:

KM>А где именно cancel устанавливается в true? Т.к в примере я этого не увидел. Может я пропустил?

Да нет, всё просто: button1(старт) вызывает эту процедуру, а button2 (стоп) ставит cancel в false.
Re: Как правильно выйти из процедуры?
От: NoOneKnows  
Дата: 20.01.07 20:30
Оценка:
Здравствуйте, Mono.m, Вы писали:

MM>Т.е. если cancel = true — отменяем всё нафик.


> [skip]


Мне вот интересно, только для меня корень ошибки кажется в абсолютно неверном архитектурном подходе к решению?
С уважением, Рамиль Сам Ду Нар.
Почти самый отрицательный
Автор: NoOneKnows
Дата: 08.06.06
РСДНовец.
Re: Как правильно выйти из процедуры?
От: vhonest  
Дата: 20.01.07 23:35
Оценка:
Здравствуйте, Mono.m, Вы писали:

MM>(сорри за табуляцию — установил последний sp, shift+tab перестал работать)


А вот выделение мышью с зажатым Alt рулит табы не хуже
Re[3]: Как правильно выйти из процедуры?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.01.07 01:42
Оценка:
Здравствуйте, Mono.m, Вы писали:

MM>Здравствуйте, kostya.misura, Вы писали:


KM>>А где именно cancel устанавливается в true? Т.к в примере я этого не увидел. Может я пропустил?

MM>Да нет, всё просто: button1(старт) вызывает эту процедуру, а button2 (стоп) ставит cancel в false.

Это код что в отдельном потоке вызвается? Такие вещи надо заранее оговоривать. Тут телепатов нет.
Чудес не бывает. Раз вызвается, значит все же cancel не ставится в тру. Или ставится поздно. Поставь точку останова в методе и когда она сработает открой колстек и посмотри чему равно поле cancel. Возможно проблема заключается в том, что код выполняется внутри анонимного метода. Это может привести к тому, что для cancel создастся поле в специально сгенерированном для анонимного метода которое проинициализируется при создании этого класса и не будет изменяться далее.

Да, использовать MemoryStream в using-е практически бессмысленно (если ты не используешь ассинхронные оповещения). Он ресурсов не занимает.

ЗЫ

А вообще оформление кода у тебя ужасное. Лишние скобки, но при этом if-ы в одну строку. Поля по именам ничем не отличаются от локальных переменных. Читать очень неудобно. В таких условиях ошибки совершенно естественны.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Как правильно выйти из процедуры?
От: Mono.m Россия  
Дата: 21.01.07 03:11
Оценка:
Здравствуйте, VladD2, Вы писали:

MM>>Да нет, всё просто: button1(старт) вызывает эту процедуру, а button2 (стоп) ставит cancel в false.

VD>Это код что в отдельном потоке вызвается? Такие вещи надо заранее оговоривать. Тут телепатов нет.
Разве в этом предложении есть намёк на выполнение в отдельном потоке?!
Да, анонимный метод вызывается асинхронно, но это понятно по коду.
Имхо, звать телепатов пока рано.

VD>Чудес не бывает. Раз вызвается, значит все же cancel не ставится в тру. Или ставится поздно.

Ставится-то ставится: всё отменяется, да вот только вызов SetStatus(...) внутри while всё-равно происходит в последний раз, хотя по идее не должен.

private void button2_Click(object sender, EventArgs e)
{
    cancel = true;
    SetStatus(barStaticItem1, "Отменено пользователем");
}

Т.е. нажимаем button2, всё отменяется и в строке состояния пишем, что отменено пользователем.
Однако, при нажатии в состоянии "загрузки" (читай внутри while) в строке состояния остаётся "Загрузка... 111 К" и всё тут.
Re[2]: Как правильно выйти из процедуры?
От: Mono.m Россия  
Дата: 21.01.07 03:19
Оценка:
Здравствуйте, NoOneKnows, Вы писали:

NOK>Мне вот интересно, только для меня корень ошибки кажется в абсолютно неверном архитектурном подходе к решению?

Просветите пожалуйста
Re[2]: Как правильно выйти из процедуры?
От: Mono.m Россия  
Дата: 21.01.07 03:21
Оценка:
Здравствуйте, vhonest, Вы писали:

V>А вот выделение мышью с зажатым Alt рулит табы не хуже

Не знал... спасибо!
Re[5]: Как правильно выйти из процедуры?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.01.07 12:46
Оценка: 3 (1)
Здравствуйте, Mono.m, Вы писали:

MM>Да, анонимный метод вызывается асинхронно, но это понятно по коду.

MM>Имхо, звать телепатов пока рано.

Для того чтобы делать такие предположения надо знать как работает BeginGetResponse(). Я с ним не знаком. Думаю, многие тоже.

MM>Ставится-то ставится: всё отменяется, да вот только вызов SetStatus(...) внутри while всё-равно происходит в последний раз, хотя по идее не должен.


Чудес не бывает. Я тебе уже говорил, поставь точку останова и посмотри колстэк.

MM>Однако, при нажатии в состоянии "загрузки" (читай внутри while) в строке состояния остаётся "Загрузка... 111 К" и всё тут.


Я вообще не понимаю что тут странного? Нажатие на твою кнопку может происходить когда угодно. В этот момент управление может находиться уже в цикле (за проверкой). Естественно, что в метод управление попадет, а не следующей итерации уже выйдет по брэйку.
То есть:
while (read > 0)
{
        if (cancel) { break; }
        read = sr.Read(buff, 0, buff.Length); // эта операция может быть длогой.
        data.Write(buff, 0, read);
        size += read;
        SetStatus(barStaticItem1, "Загрузка…");
        SetStatus(barStaticItem2, string.Format("{0} K", size / 1024));
}

если предположить, что sr.Read() долгая операция, то не мудренно, что после нажатия на кнопку сначала пишется твоя надписаь, а потом код продолжается с data.Write() и далее надпись меняется на "Загрузка…".

И вообще еще надо смотреть как реализован метод SetStatus(). Он же должен к объектам принадлежащим к GUI-потоку обращаться. Там может быть блокировка.

Перепиши код так:
while (read > 0)
{
if (cancel)
break;
read = sr.Read(buff, 0, buff.Length);
data.Write(buff, 0, read);
size += read;
if (cancel)
break;
else
{
SetStatus(barStaticItem1, "Загрузка…");
SetStatus(barStaticItem2, string.Format("{0} K", size / 1024));
}
}
[/c#]
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Как правильно выйти из процедуры?
От: NoOneKnows  
Дата: 21.01.07 13:08
Оценка:
Здравствуйте, Mono.m, Вы писали:

MM>Просветите пожалуйста


Хм . Я ж не гуру, но думаю, проблем не было бы, если бы изначально задумались о выносе бизнес-логики в отдельный тип. А подписчик события нажатия на кнопку Сансел (или как там она звалась?) делегировал бы останов time-consuming операции ответственному типу.

А так у вас есть один МегаТип, который пытается обрабатывать данные и тут же по месту обращаться к ГУИ. У меня такой код ассоциируется с чокнутым программистом, денно и нощно сидящим за компом, обросшим банками пива и грязи во всепоглащающем хаосе ... Сорри.

Впрочем, VladD2 уже сказал об "ужасном оформлении кода". Не отчаивайтесь, есть много замечтельных книг, которые могли бы исправить положение, (Совершенный код
Автор(ы): Стив Макконнелл

Опираясь на академические исследования, с одной стороны, и практический
опыт коммерческих разработок ПО — с другой, автор синтезировал из самых
эффективных методик и наиболее эффективных принципов ясное прагматичное
руководство. Каков бы ни был ваш профессиональный уровень, с какими бы
средствами разработками вы ни работали, какова бы ни была сложность вашего
проекта, в этой книге вы найдете нужную информацию, она заставит вас
размышлять и поможет создать совершенный код. Книга состоит из 35 глав,
предметного указателя и библиографии.
, Программист-прагматик
Автор(ы): Эндрю Хант, Дэвид Томас
Издательство: Лори
Цена: 333р.

Находясь на переднем крае программирования, книга "Программист-прагматик" абстрагируется от всевозрастающей специализации и технических тонкостей разработки программ на современном уровне, чтобы исследовать суть процесса — требования к
, МЧМ
Автор(ы): Фредерик Брукс
Эта книга — юбилейное (дополненное и исправленное) издание своего рода библии для разработчиков программного обеспечения во всем мире, написанное Бруксом еще в 1975 году. Тогда же книга была издана на русском языке и давно уже стала библиографической редкостью. В США полагают, что без прочтения книги Брукса не может состояться ни один крупный руководитель программного проекта. Если вы никогда не слышали об этой книге, вы можете поискать ссылки на нее в Интернете (Frederick P. Brooks, The Mythical Man-Month). Вам все сразу станет понятно.
)
С уважением, Рамиль Сам Ду Нар.
Почти самый отрицательный
Автор: NoOneKnows
Дата: 08.06.06
РСДНовец.
Re[6]: Как правильно выйти из процедуры?
От: Mono.m Россия  
Дата: 21.01.07 13:56
Оценка:
Здравствуйте, VladD2, Вы писали:

while (read > 0)
{
        if (cancel)
            break;
        read = sr.Read(buff, 0, buff.Length);
        data.Write(buff, 0, read);
        size += read;
        if (cancel)
            break;
        else
        {
            SetStatus(barStaticItem1, "Загрузка…");
            SetStatus(barStaticItem2, string.Format("{0} K", size / 1024));
        }
}


Вот это помогло, спасибо!
Re[4]: Как правильно выйти из процедуры?
От: Mono.m Россия  
Дата: 21.01.07 13:59
Оценка:
Здравствуйте, NoOneKnows, Вы писали:

NOK>Здравствуйте, Mono.m, Вы писали:


MM>>Просветите пожалуйста


NOK>Хм . Я ж не гуру, но думаю, проблем не было бы, если бы изначально задумались о выносе бизнес-логики в отдельный тип. А подписчик события нажатия на кнопку Сансел (или как там она звалась?) делегировал бы останов time-consuming операции ответственному типу.


NOK>А так у вас есть один МегаТип, который пытается обрабатывать данные и тут же по месту обращаться к ГУИ. У меня такой код ассоциируется с чокнутым программистом, денно и нощно сидящим за компом, обросшим банками пива и грязи во всепоглащающем хаосе ... Сорри.


По сути, вся программа — это этот код + парсер, поэтому выносить всё в отдельные классы не стал.
Re[6]: Как правильно выйти из процедуры?
От: .Den Украина  
Дата: 22.01.07 07:59
Оценка:
Здравствуйте, VladD2, Вы писали:


VD>То есть:

VD>
VD>while (read > 0)
VD>{
VD>        if (cancel) { break; }
VD>        read = sr.Read(buff, 0, buff.Length); // эта операция может быть длогой.
VD>        data.Write(buff, 0, read);
VD>        size += read;
VD>        SetStatus(barStaticItem1, "Загрузка…");
VD>        SetStatus(barStaticItem2, string.Format("{0} K", size / 1024));
VD>}
VD>

VD>если предположить, что sr.Read() долгая операция, то не мудренно, что после нажатия на кнопку сначала пишется твоя надписаь, а потом код продолжается с data.Write() и далее надпись меняется на "Загрузка…".


Тем не мение и такой подход не является очень хорошим (хотя и получше пнрвого), т.к. в некоторых случаях (например по завершению SetStatus(barStaticItem1, "Загрузка…"), выставится результат завершения, а затем... хм, не то что нужно (SetStatus(barStaticItem2, string.Format("{0} K", size / 1024))
Re[7]: Как правильно выйти из процедуры?
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.01.07 10:21
Оценка:
Здравствуйте, .Den, Вы писали:

D>Тем не мение и такой подход не является очень хорошим (хотя и получше пнрвого), т.к. в некоторых случаях (например по завершению SetStatus(barStaticItem1, "Загрузка…"), выставится результат завершения, а затем... хм, не то что нужно (SetStatus(barStaticItem2, string.Format("{0} K", size / 1024))


В общем — да. Здесь по уму нужно использовать блокировку. Но в принципе вероятность появления проблем очень мала. Так что если код не критичный, то можно забить. Только я бы первую проерку тоже махнул бы.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Как правильно выйти из процедуры?
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.01.07 10:21
Оценка: +1
Здравствуйте, Mono.m, Вы писали:

MM>По сути, вся программа — это этот код + парсер, поэтому выносить всё в отдельные классы не стал.


Откровенно говоря размер программы, да и другие критерии, не должны влиять на правильность дизайна. Эта такая область где привычки очень важны. Если ты пишешь много мелких программ и забиваешь, в следствии этого, на качество дизайна кода, то когда ты переходишь к большим программам, то на дизайн ты начинашь чихать уже по привычки.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Как правильно выйти из процедуры?
От: Mono.m Россия  
Дата: 22.01.07 11:28
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Откровенно говоря размер программы, да и другие критерии, не должны влиять на правильность дизайна. Эта такая область где привычки очень важны. Если ты пишешь много мелких программ и забиваешь, в следствии этого, на качество дизайна кода, то когда ты переходишь к большим программам, то на дизайн ты начинашь чихать уже по привычки.


Гопода, Москва не сразу строилась...

Всю жизнь сидел на VB6, потом VB.NET. Вот недавно стал изучать C# (и не зря )
Re[4]: Как правильно выйти из процедуры?
От: Аноним  
Дата: 21.01.07 07:55
Оценка:
Mono.m:
Здравствуйте, VladD2, Вы писали:

MM]]Да нет, всё просто: button1(старт) вызывает эту процедуру, а button2 (стоп) ставит cancel в false.
VD]Это код что в отдельном потоке вызвается? Такие вещи надо заранее оговоривать. Тут телепатов нет.
Разве в этом предложении есть намёк на выполнение в отдельном потоке?!
Да, анонимный метод вызывается асинхронно, но это понятно по коду.
Имхо, звать телепатов пока рано.

VD]Чудес не бывает. Раз вызвается, значит все же cancel не ставится в тру. Или ставится поздно.
Ставится-то ставится: всё отменяется, да вот только вызов SetStatus(...) внутри while всё-равно происходит в последний раз, хотя по идее не должен.


private void button2_Click(object sender, EventArgs e)
{
cancel = true;
SetStatus(barStaticItem1, "Отменено пользователем");
}
Т.е. нажимаем button2, всё отменяется и в строке состояния пишем, что отменено пользователем.
Однако, при нажатии в состоянии "загрузки" (читай внутри while) в строке состояния остаётся "Загрузка... 111 К" и всё тут.

Всё правильно. Ты выставляешь "cancel = true" и сразуже, не дожидаясь отмены выставляешь статус, а далеко не факт, что твой делегат уже всё отменил на тот момент. Делегат еще читает текущий блок и честно выставляет статус, затирая твой "Отменено". И только после текущего блока узнает, что всё отменяется и прекращает работу. Асинхронность, однако.
"обвинение в злостном использовании своих гражданских прав" (из реального)
| Мой Brainbench | BookReader 1.1 | Wallpaper Cycler |


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[4]: Как правильно выйти из процедуры?
От: Аноним  
Дата: 21.01.07 07:57
Оценка:
вставь после чтения очередного блока
if(!cancel)
{
  SetStatus(barStaticItem1, "Загрузка…");
  SetStatus(barStaticItem2, string.Format("{0} K", size / 1024));
}
"обвинение в злостном использовании своих гражданских прав" (из реального)
| Мой Brainbench | BookReader 1.1 | Wallpaper Cycler |


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[6]: Как правильно выйти из процедуры?
От: Аноним  
Дата: 22.01.07 08:15
Оценка:
.Den:
Здравствуйте, VladD2, Вы писали:


VD]То есть:
VD]
VD]while (read ] 0)
VD]{
VD] if (cancel) { break; }
VD] read = sr.Read(buff, 0, buff.Length); // эта операция может быть длогой.
VD] data.Write(buff, 0, read);
VD] size += read;
VD] SetStatus(barStaticItem1, "Загрузка…");
VD] SetStatus(barStaticItem2, string.Format("{0} K", size / 1024));
VD]}
VD]
VD]если предположить, что sr.Read() долгая операция, то не мудренно, что после нажатия на кнопку сначала пишется твоя надписаь, а потом код продолжается с data.Write() и далее надпись меняется на "Загрузка…".


Тем не мение и такой подход не является очень хорошим (хотя и получше пнрвого), т.к. в некоторых случаях (например по завершению SetStatus(barStaticItem1, "Загрузка…"), выставится результат завершения, а затем... хм, не то что нужно (SetStatus(barStaticItem2, string.Format("{0} K", size / 1024))

А ты код внимательно прочитал?
"обвинение в злостном использовании своих гражданских прав" (из реального)
| Мой Brainbench | BookReader 1.1 | Wallpaper Cycler |


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.