N_P>>А еще сеть может отвалиться на минутку и надо-бы попробовать раз 5 повторить чтение с задержкой.
0K>Если пользователь дал добро создать файл -- значит можно затирать.
Да ни в коем случае! Он может быть просто некомпетентен в этом! Может там строка соединения к БД регистрации, которую админ перед началом работы комплекса настраивает спец-утилитой ? Юзер про то и знать-то не знает — скрыто это от него.
не знаю был ли тут этот вопрос, но
что если после чтения счетчик был изменен кем-то из вне? (напр. другим экземпляром программы)
надо ли при записи сравнивать значение счетчика в файле с прочитанным?
Здравствуйте, Muxa, Вы писали:
M>поменьше слов, побольше кода. (c)
Спасибо.
Теперь критика:
По существу:
1. Если файл при чтении занят другим процессом, возникает непредвиденная вашей программой ошибка:
Произошла непредвиденная ошибка. Обратитесь к разработчику.
System.IO.IOException: The process cannot access the file 'C:\Users\User\AppDat
a\Local\Temporary Projects\ConsoleApplication1\bin\Debug\f' because it is being
used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, I
nt32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions o
ptions, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolea
n useLongPath)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access,
FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detec
tEncodingFromByteOrderMarks, Int32 bufferSize)
at System.IO.FileInfo.OpenText()
at ConsoleApplication1.FileIncrementor.Read() in C:\Users\User\AppData\Local
\Temporary Projects\ConsoleApplication1\Program.cs:line 76
at ConsoleApplication1.Program.Main() in C:\Users\User\AppData\Local\Tempora
ry Projects\ConsoleApplication1\Program.cs:line 18
Еще раз? (y/Y/д/Д/Ввод = ДА, остальное = НЕТ)
Не думаю, что из-за подобной чепухи нужно беспокоить разработчика. Программы должны работать а рарзработчик отдыхать
Так что, как видите, стратегия Neco перехватить базовый Exception на практике оказалась намного прочнее. Вы все-таки забыли обработать IOException (И не удивительно, т.к. посчитайте сколько их там этих исключений и нет ни единой возможности обработать все пачкой).
Дополнительно:
1. Неправильно наследуете Exception. Нужно имплеменитровать все конструкторы + пометить класс Serializable. Если добавляете свои свойства -- они должны быть сериализуемыми (у вас не нужно). Класс исключения должен быть public.
2. При string.Format вам нужно указать CultureInfo.InvariantCulture, иначе все преобразуется с поправкой на текущую культуру. Это обязательно писать.
Здравствуйте, Nikolay_P_I, Вы писали:
N_P>Да ни в коем случае! Он может быть просто некомпетентен в этом! Может там строка соединения к БД регистрации, которую админ перед началом работы комплекса настраивает спец-утилитой ? Юзер про то и знать-то не знает — скрыто это от него.
А вообще при недоступности сети будет не FileNotFoundException... Так что проблема надумана.
0K>1. Неправильно наследуете Exception. Нужно имплеменитровать все конструкторы + пометить класс Serializable. Если добавляете свои свойства -- они должны быть сериализуемыми (у вас не нужно). Класс исключения должен быть public.
стыдно спросить, но зачем? (все конструкторы, сериализуемость, и паблик (это, кстати, решарпер изменил на интёрнал))
Здравствуйте, gandjustas, Вы писали:
G>Нивопрос, давай свои юзкейсы, только чтобы они были риальными, мы же риальное приложение пишем
Все что нужно было сделать -- описано в первом и втором сообщении. Как минимум 4 человека прекрасно меня поняли и даже реализовали требования в виде кода. Вы же только всех критикуете.
Специально для таких как вы, напишу по пунктам. Надеюсь диаграммы не заставите рисовать
Итак. Нужна библиотека, которую можно задействовать в Windows или консольном приложении. Желательно без особых заморочек (как подписывание на события). Кроме того, нужно продемонстровать использование этой библиотеки с консольным приложением (нужен код консольного приложения и библиотеки). Это требование было во втором сообщении.
Как все должно работать:
1. Вводим название счетчика. Название счетчика должно соответствовать файлу в любой из папок (можно использовать текущую папку проекта -- не важно). Нельзя допускать, чтобы 2 счетчика с разным названием имели один и тот же файл.
2. Если название счетчика некорректно, выдаем сообщение об ошибке (можно любое не тратьте время на обдумывание текста, его заменят другие) и предоставляем возможность ввести другое название.
3. Если файл со счетчиком не существует -- спрашиваем создать ли его. Разрешение получено -- создаем, иначе -- датем возможность ввести другое имя счетчика (без выхода из программы).
4. Пытаемся прочесть файл. Если прочесть не удалось -- вывести 2 сообщения: для обычных пользователей(ака проблема с чтением файла) и детали для админа (почему не удалось прочесть). Предоставить возможность повторить повторить попытку чтения или выйти из программы/начать все заново.
5. Пытаемся преобразовать текст из файла к целому положительному числу. Если преобразовать не удалось или если файл пустой (новый) -- даем возможность установить значение счетчика (для упрощения можно автоматически устанавливать 0).
6. Увеличиваем число, прочтенное из файла, на 1.
7. Сохраняем новое значение числа в тот же файл, из которого прочли. Если сохранить не удалось -- вывести 2 сообщения: для обычных пользователей(ака проблема с чтением файла) и детали для админа (почему не удалось прочесть).
8. Дать возможность повторить процесс.
Все это умные люди поняли из первого сообщения и даже привели решения.
Здравствуйте, Muxa, Вы писали:
M>стыдно спросить, но зачем? (все конструкторы, сериализуемость, и паблик (это, кстати, решарпер изменил на интёрнал))
Public, т.к. исключение может "выйти" за пределы вашей библиотеки. Просто забудете его перехватить -- и все. А как его ловить выше? По базовому Exception?
Сериализация -- нужна, т.к. исключения иногда "выбрасывают" удаленно (в другом домене или вообще на другой машине в другой части света ). Это просто рекомендация MS, в нашей программе это смысла не имеет.
Все конструкторы -- не знаю сам -- это рекомендация MS. Разве что protected-конструктор, который используется в сериализации закрывать не стоит. Да и то, если ваш Exception sealed и вы явно не добавляете новых сериализуемых свойств -- смысла нет.
Здравствуйте, 0K, Вы писали:
0K>Здравствуйте, Muxa, Вы писали:
M>>стыдно спросить, но зачем? (все конструкторы, сериализуемость, и паблик (это, кстати, решарпер изменил на интёрнал))
0K>Public, т.к. исключение может "выйти" за пределы вашей библиотеки. Просто забудете его перехватить -- и все. А как его ловить выше? По базовому Exception?
Нет требований к видимости исключений. Это самодеятельность. Может "выйти" а может и не "выйти".
0K>Сериализация -- нужна, т.к. исключения иногда "выбрасывают" удаленно.
Иногда код вызывают удаленно.
0K> Это просто рекомендация MS, в нашей программе это смысла не имеет.
Это не рекомендация, это требование. Смысл имеет, т.к. любой код может быть вызван удаленно.
0K>Все конструкторы -- не знаю сам -- это рекомендация MS.
Это не рекомендация, это посильнее.
0K>Разве что protected-конструктор, который используется в сериализации закрывать не стоит. Да и то, если ваш Exception sealed и вы явно не добавляете новых сериализуемых свойств -- смысла нет.
Без спецконструктора не будет сериалиации, в том числе у наследников. Спецконструктор — требование.
Здравствуйте, 0K, Вы писали:
0K>Как все должно работать:
Наконец, удалось вымучить описание задачи. И двух дней не прошло.
Можно сравнить с первым сообщением, и увидеть, как сильно они отличаются.
И как повлияли предложенные решения и дискуссия на формулировки в описании.
0K>Все это умные люди поняли из первого сообщения и даже привели решения.
Unhandled Exception: Обнаружена попытка надавить на эмоции. Игнорируется.
M>>стыдно спросить, но зачем? (все конструкторы, сериализуемость, и паблик (это, кстати, решарпер изменил на интёрнал))
0K>Public, т.к. исключение может "выйти" за пределы вашей библиотеки. Просто забудете его перехватить -- и все. А как его ловить выше? По базовому Exception?
ааа, это если проект оформлять в виде exe+dll тогда конечно (просто только сейчас нашел комментарий что должна быть отдельная сборка работы со счетчиками). я же отлавливаю свои исключения в вызывающем коде, если б солюшен был бы в виде программа+сборка, то и исключение было бы публичное, иначе синтакс еррор.
если бы я был автором только сборки, когда необходимо предусмотреть, что автор вызывающего кода захочет перехватывать мои исключения, и сделать их заранее публичными.
Здравствуйте, 0K, Вы писали:
0K>Здравствуйте, gandjustas, Вы писали:
G>>Нивопрос, давай свои юзкейсы, только чтобы они были риальными, мы же риальное приложение пишем
0K>Все что нужно было сделать -- описано в первом и втором сообщении. Как минимум 4 человека прекрасно меня поняли и даже реализовали требования в виде кода. Вы же только всех критикуете.
0K>Специально для таких как вы, напишу по пунктам. Надеюсь диаграммы не заставите рисовать
0K>Итак. Нужна библиотека, которую можно задействовать в Windows или консольном приложении. Желательно без особых заморочек (как подписывание на события). Кроме того, нужно продемонстровать использование этой библиотеки с консольным приложением (нужен код консольного приложения и библиотеки). Это требование было во втором сообщении.
0K>Как все должно работать:
0K>1. Вводим название счетчика. Название счетчика должно соответствовать файлу в любой из папок (можно использовать текущую папку проекта -- не важно). Нельзя допускать, чтобы 2 счетчика с разным названием имели один и тот же файл. 0K>2. Если название счетчика некорректно, выдаем сообщение об ошибке (можно любое не тратьте время на обдумывание текста, его заменят другие) и предоставляем возможность ввести другое название. 0K>3. Если файл со счетчиком не существует -- спрашиваем создать ли его. Разрешение получено -- создаем, иначе -- датем возможность ввести другое имя счетчика (без выхода из программы). 0K>4. Пытаемся прочесть файл. Если прочесть не удалось -- вывести 2 сообщения: для обычных пользователей(ака проблема с чтением файла) и детали для админа (почему не удалось прочесть). Предоставить возможность повторить повторить попытку чтения или выйти из программы/начать все заново. 0K>5. Пытаемся преобразовать текст из файла к целому положительному числу. Если преобразовать не удалось или если файл пустой (новый) -- даем возможность установить значение счетчика (для упрощения можно автоматически устанавливать 0). 0K>6. Увеличиваем число, прочтенное из файла, на 1. 0K>7. Сохраняем новое значение числа в тот же файл, из которого прочли. Если сохранить не удалось -- вывести 2 сообщения: для обычных пользователей(ака проблема с чтением файла) и детали для админа (почему не удалось прочесть). 0K>8. Дать возможность повторить процесс.
0K>Все это умные люди поняли из первого сообщения и даже привели решения.
Во-первых ты снова описываешь что должна делать программа, а я спрашиваю зачем. Ты думаешь в в риальном случае будет приходить заказчик и рассказывать о каких-то там файлах в папках?
Во-вторых если нужна библиотека, как ты сам написал, то никакого user interaction там не будет в принципе, поэтому "как все должно работать" идет лесом.
Опиши цели (для пользователя) и юзкейсы, тогда продолжим.
Здравствуйте, Neco, Вы писали:
N>Здравствуйте, fmiracle, Вы писали:
F>>Вот их надо отловить и завернуть в твой IncrementorException. В идеале с уточняющими полями, что именно было не так и с тем чтобы дальше иметь возможность показать пользователю сообщение различного вида в зависимости от проблемы. N>Ага. Что-то начинаю понимать, но для полной ясности мне надо понять, что должен делать с этим вышестоящий класс. Не мог бы ты описать или пример привести?
Класс будет делать то, что ему надо и что диктуется общей логикой программы. На примере рассматривамой программки это неясно, но должно быть яснее, если этот инкрементатор — это только часть более общей системы. И тогда удобно, что исключения из различных источников не перекрывают друг друга.
Ну вот рассмотрим как раз пример, что инкрементор стал реализован через Оракл (или даже так же реализован через файлы, с опциональной настройкой где-то в конфигурации какое решение использовать). При этом работа с доступом управляется извне класса (это нормально — например, для проведения изменений, созданных классом в общей транзакции)
код не реальный, а только ключевые моменты выделены с заметными упрощениями
class OracleIncrementor : IIncrementor
{
public Increment()
{
var dbManager = Ioc.Resolve<IDbManager>();
//провести инкрементацию чего надо через dbManager.
}
}
class Main
{
public User LoginUser( string login, string pass )
{
try
{
var dbManager = Ioc.Resolve<IDbManager>();
var user = dbManager.SearchUserByLoginAndPass( login, pass );
if( user == null )
{
throw new NoAccessException("Пользователь с таким логином или паролем не зарегистрирован в системе");
}
using( var tran = dbManager.BeginTransaction() )
{
//у пользователя обновляем дату последного захода в систему
user.LastLoginTime = DateTime.Now;
dbManager.Save(user);
//при логине мы так же обновляем специальный сторонний счетчик заходовtry
{
var incrementor = Ioc.Resolve<IIncrementor>( "userLogons" );
incrementor.Increment();
}
catch( IncrementorException iex )
{
//тут решаем что делать с ошибкой инкрементации.
//считается, что сюда попадают только те ошибки, которые не смог решить сам инкрементор.
//Если нам эта инкрементация не очень-то и важна, то просто пишем в лог и подавляем ошибку.
//а если важна (может быть для какой-то интеграции) и работа без нее продолжена быть не может
//то этого блока try/catch тут просто не будет и ошибка сама собой уйдет выше.
}
tran.CommitTransaction();
return user;
}
}
catch( DbException dex )
{
//а вот это уже для нас серьезно - у нас сбой базы данных. То ли не можем приконнектиться
//то ли структура базы не соответствует ожидаемой
//в общем - надо думать
//как минимум можно переложить идею подумать пользователю, вывалив ему эту ошибку наверх
//а можно попробовать покопаться в кишках DbException и понять
//что именно у нас произошло, и можно ли сделать что-то для исправления
//(например, у нас может быть требование к программе, что при сбое соединения, надо подождать,
//и еще два раза попробовать соединиться, и только потом уже отключаться).
//или можно запустить обновлятор базы и если он успешно что-то обновит - то попробовать провести повторный логин.
//и совсем даже не факт, что это должно обрабатываться в данном методе а не где-то выше.
}
}
}
В твоем варианте последняя DbException, если возникала в случае работы с Инкрементором (например, при выдергивании шнурка из сервера во время обработки) пришла бы наверх в виде IncrementoException и попала бы в ветку обработки, в которой не предполагалось решать какие-либо проблемы с базой.
При этом, например, ошибка, что сиквенс, который мы используем для ведения инкрементации есть, но его значение уже равно максимальному — это IncrementorException, и описываеся оно как "Достигнуто максимальное значение, дальнейшее увеличение невозможно".
А вот ошибка, что последовательность вообще отсутствует — это скорее всего не IncrementorException, потому что с большой вероятностью — это общая проблема с базой. Очень вероятно, что просто подключились не к той базе. Или структура база не была обновлена до нужной версии приложения. И обрабатывать эту проблему надо наравне с остальными проблемами несоответствия структуры базы ожидаемой.
Здравствуйте, 0K, Вы писали:
0K>1. Если файл при чтении занят другим процессом, возникает непредвиденная вашей программой ошибка:
0K>
0K>Произошла непредвиденная ошибка. Обратитесь к разработчику.
0K>System.IO.IOException: The process cannot access the file 'C:\Users\User\AppDat
0K>a\Local\Temporary Projects\ConsoleApplication1\bin\Debug\f' because it is being
0K>used by another process.
....
0K>Еще раз? (y/Y/д/Д/Ввод = ДА, остальное = НЕТ)
0K>Не думаю, что из-за подобной чепухи нужно беспокоить разработчика. Программы должны работать а рарзработчик отдыхать
0K>Так что, как видите, стратегия Neco перехватить базовый Exception на практике оказалась намного прочнее. Вы все-таки забыли обработать IOException (И не удивительно, т.к. посчитайте сколько их там этих исключений и нет ни единой возможности обработать все пачкой).
Вообще-то, принципиальной разницы нету, поскольку тут тоже стоит обработка базового Exception. Программа не упала, ничего не испортила, просто посоветовала обратиться к разработчику и написала подробную информацию об ошибке. Вариант Neco в этом случае написал бы ровно то же самое, но другими словами, что не мудрено, поскольку оперирует тем же IOException.Message и выводит IOException в качестве деталей.
Серьезная разница только в том, что Neco не рекомендует обращаться к разработчику и не называет ошибку, которую он не продумывал, "непредвиденной". Да, это очень, очень серьезная разница. Сон разработчика — дело святое.
Здравствуйте, akasoft, Вы писали:
A>Читаем дальше. В строке 04 видим разбор полученного на предыдущем шаге значения. Тут мы можем словить FormatException, если окажется, что то, что мы проситали — не число. Реагируем на из предположения (тут включилась Боевая Телепатия, в коде про это ничего нет!), что если там чёртичто, то должен быть сбоку бантик, т.е. "-1":
Еще может быть OverflowException, если там число, но очень, очень большое.
Но что с ним делать автор все равно не рассказал... Я лично и этот случай (как и некорректный формат) понял так, что ничего писать не надо. А ты понял прямо наоборот.
Видимо это все потому (как утверждает автор в первых постах темы), что мы с тобой тупые кодеры, за которых надо думать
Здравствуйте, Muxa, Вы писали:
M>не знаю был ли тут этот вопрос, но M>что если после чтения счетчик был изменен кем-то из вне? (напр. другим экземпляром программы) M>надо ли при записи сравнивать значение счетчика в файле с прочитанным?
И что делать, если между сравнением счетчика в файле при записи и собственно записью, произошло опять же стороннее изменение? Может надо еще раз проверить соответствие?
F>И что делать, если между сравнением счетчика в файле при записи и собственно записью, произошло опять же стороннее изменение? Может надо еще раз проверить соответствие?
алгоритм записи:
открыть файл на чтение-запись, сравнить, если все ок, записать, иначе "хз".
так никто не вклинится.
осталось понять чему равно "хз".
Здравствуйте, Muxa, Вы писали:
F>>И что делать, если между сравнением счетчика в файле при записи и собственно записью, произошло опять же стороннее изменение? Может надо еще раз проверить соответствие? M>алгоритм записи: M>открыть файл на чтение-запись, сравнить, если все ок, записать, иначе "хз". M>так никто не вклинится. M>осталось понять чему равно "хз".
Ну тогда надо открыть на чтение/запись сразу же еще при первом обращении за значением счетчика (операция-то над данными простая и недлительная — распарсить и инкрементировать). А "хз" будет у той абстрактной программы, которая с этим файлом работает и попробует в этот момент обратиться к файлу
Но это всегда может быть — все равно какое-то время в файл пишем.
Здравствуйте, fmiracle, Вы писали:
F>И что делать, если между сравнением счетчика в файле при записи и собственно записью, произошло опять же стороннее изменение? Может надо еще раз проверить соответствие?
Лучше всего запретить другим процессам открывать файл (кстати, MS Office так и делает).