Здравствуйте, Mono.m, Вы писали:
MM> нужно ли использовать resp.Close()? или объект resp закроется автоматически, т.к. внутри Using?
Для меня это до сих пор нерешенный вопрос. Лично, я тихонечко не люблю классы которые реализуют IDisposable и при этом предоставляют методы типа public Close. В каждом конеретном случае я лезу рефлектором, что бы удостоверится что Dispose вызывает этот метод. В Вашем случае это так:
Здравствуйте, kostya.misura, Вы писали:
KM>А где именно cancel устанавливается в true? Т.к в примере я этого не увидел. Может я пропустил?
Да нет, всё просто: button1(старт) вызывает эту процедуру, а button2 (стоп) ставит cancel в false.
Здравствуйте, 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>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
MM>>Да нет, всё просто: button1(старт) вызывает эту процедуру, а button2 (стоп) ставит cancel в false. VD>Это код что в отдельном потоке вызвается? Такие вещи надо заранее оговоривать. Тут телепатов нет.
Разве в этом предложении есть намёк на выполнение в отдельном потоке?!
Да, анонимный метод вызывается асинхронно, но это понятно по коду.
Имхо, звать телепатов пока рано.
VD>Чудес не бывает. Раз вызвается, значит все же cancel не ставится в тру. Или ставится поздно.
Ставится-то ставится: всё отменяется, да вот только вызов SetStatus(...) внутри while всё-равно происходит в последний раз, хотя по идее не должен.
Т.е. нажимаем button2, всё отменяется и в строке состояния пишем, что отменено пользователем.
Однако, при нажатии в состоянии "загрузки" (читай внутри while) в строке состояния остаётся "Загрузка... 111 К" и всё тут.
Здравствуйте, NoOneKnows, Вы писали:
NOK>Мне вот интересно, только для меня корень ошибки кажется в абсолютно неверном архитектурном подходе к решению?
Просветите пожалуйста
Здравствуйте, 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>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Mono.m, Вы писали:
MM>Просветите пожалуйста
Хм . Я ж не гуру, но думаю, проблем не было бы, если бы изначально задумались о выносе бизнес-логики в отдельный тип. А подписчик события нажатия на кнопку Сансел (или как там она звалась?) делегировал бы останов time-consuming операции ответственному типу.
А так у вас есть один МегаТип, который пытается обрабатывать данные и тут же по месту обращаться к ГУИ. У меня такой код ассоциируется с чокнутым программистом, денно и нощно сидящим за компом, обросшим банками пива и грязи во всепоглащающем хаосе ... Сорри.
Впрочем, VladD2 уже сказал об "ужасном оформлении кода". Не отчаивайтесь, есть много замечтельных книг, которые могли бы исправить положение, (Совершенный код
Здравствуйте, NoOneKnows, Вы писали:
NOK>Здравствуйте, Mono.m, Вы писали:
MM>>Просветите пожалуйста
NOK>Хм . Я ж не гуру, но думаю, проблем не было бы, если бы изначально задумались о выносе бизнес-логики в отдельный тип. А подписчик события нажатия на кнопку Сансел (или как там она звалась?) делегировал бы останов time-consuming операции ответственному типу.
NOK>А так у вас есть один МегаТип, который пытается обрабатывать данные и тут же по месту обращаться к ГУИ. У меня такой код ассоциируется с чокнутым программистом, денно и нощно сидящим за компом, обросшим банками пива и грязи во всепоглащающем хаосе ... Сорри.
По сути, вся программа — это этот код + парсер, поэтому выносить всё в отдельные классы не стал.
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))
Здравствуйте, .Den, Вы писали:
D>Тем не мение и такой подход не является очень хорошим (хотя и получше пнрвого), т.к. в некоторых случаях (например по завершению SetStatus(barStaticItem1, "Загрузка…"), выставится результат завершения, а затем... хм, не то что нужно (SetStatus(barStaticItem2, string.Format("{0} K", size / 1024))
В общем — да. Здесь по уму нужно использовать блокировку. Но в принципе вероятность появления проблем очень мала. Так что если код не критичный, то можно забить. Только я бы первую проерку тоже махнул бы.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Mono.m, Вы писали:
MM>По сути, вся программа — это этот код + парсер, поэтому выносить всё в отдельные классы не стал.
Откровенно говоря размер программы, да и другие критерии, не должны влиять на правильность дизайна. Эта такая область где привычки очень важны. Если ты пишешь много мелких программ и забиваешь, в следствии этого, на качество дизайна кода, то когда ты переходишь к большим программам, то на дизайн ты начинашь чихать уже по привычки.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Откровенно говоря размер программы, да и другие критерии, не должны влиять на правильность дизайна. Эта такая область где привычки очень важны. Если ты пишешь много мелких программ и забиваешь, в следствии этого, на качество дизайна кода, то когда ты переходишь к большим программам, то на дизайн ты начинашь чихать уже по привычки.
Гопода, Москва не сразу строилась...
Всю жизнь сидел на VB6, потом VB.NET. Вот недавно стал изучать C# (и не зря )
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" и сразуже, не дожидаясь отмены выставляешь статус, а далеко не факт, что твой делегат уже всё отменил на тот момент. Делегат еще читает текущий блок и честно выставляет статус, затирая твой "Отменено". И только после текущего блока узнает, что всё отменяется и прекращает работу. Асинхронность, однако.
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))