Что-то почти всегда минусов от исключений больше чем плюсов ...
например такой пример:
class Program
{
static void Fx()
{
FileStream f = new FileStream("D:\\1.txt",FileMode.Append);
f.Write(UnicodeEncoding.UTF8.GetBytes("zzz"));
throw new Exception("test");//предположим вызвалось в процессе работы исключение!!!
f.Close();
}
static void Main(string[] args)
{
try {
Fx();
}
catch (Exception e)
{
Console.WriteLine("zzz");
}
Console.WriteLine("Hello World!");
}
}
во время выполнения Console.WriteLine("zzz"); Файл "D:\\1.txt" остаётся открытым и не записывается
А если подобное исключение вызывает нехорошее состояние обекта — то даже правильный GC не поможет!!!
Править такое ГГ надоедает...
Правлю я в стиле:
Можно вобще не обрабатывать — закроется с ошибкой (типо почти нормально?) — но какой тогда смысл в их использовании???
Может подскажите как меньшими силами обходит похожие грабли ???
using (FileStream fs = File.OpenRead(path))
{
byte[] b = new byte[1024];
UTF8Encoding temp = new UTF8Encoding(true);
while (fs.Read(b,0,b.Length) > 0)
{
Console.WriteLine(temp.GetString(b));
}
}
И даже не заморачиваются с закрыванием.
В общем, на Stack Overflow уже поднималась проблема и есть решение.
VYR>во время выполнения Console.WriteLine("zzz"); Файл "D:\\1.txt" остаётся открытым и не записывается VYR>А если подобное исключение вызывает нехорошее состояние обекта — то даже правильный GC не поможет!!!
Для таких случаев предназначен блок finally. Обычно в нем освобождают ресуры.
Здравствуйте, Maniacal, Вы писали:
M>Здравствуйте, vvv848165@ya.ru, Вы писали:
M>А для FileStream обязательно нужен new?
M>В примерах Microsoft пишут M>
M>using (FileStream fs = File.OpenRead(path))
M>{
M> byte[] b = new byte[1024];
M> UTF8Encoding temp = new UTF8Encoding(true);
M> while (fs.Read(b,0,b.Length) > 0)
M> {
M> Console.WriteLine(temp.GetString(b));
M> }
M>}
M>
M>И даже не заморачиваются с закрыванием.
FileStream fs — а если он нужен в качестве свойства в классе?
Здравствуйте, Буравчик, Вы писали:
Б>Здравствуйте, vvv848165@ya.ru, Вы писали:
VYR>>во время выполнения Console.WriteLine("zzz"); Файл "D:\\1.txt" остаётся открытым и не записывается VYR>>А если подобное исключение вызывает нехорошее состояние обекта — то даже правильный GC не поможет!!!
Б>Для таких случаев предназначен блок finally. Обычно в нем освобождают ресуры.
а не всёравно где бороду писать???
Здравствуйте, vvv848165@ya.ru, Вы писали:
Б>>Для таких случаев предназначен блок finally. Обычно в нем освобождают ресуры. VYR> а не всёравно где бороду писать???
Нет, не все равно. finally гарантирует освобождение ресурса, даже при наличии исключений.
В других местах — гарантий нет.
Здравствуйте, vvv848165@ya.ru, Вы писали:
Б>>Для таких случаев предназначен блок finally. Обычно в нем освобождают ресуры. VYR> а не всёравно где бороду писать???
Не всё равно. Конструкция try/catch/finally, или даже try/finally. Делать же catch ради высвобождения ресурсов — вредно.
Проблема, в том, что одни люди не понимают как работать с исключениями, а вторые — не совсем еще осознали, что GC лишь помогает, а детерминированное управление ресурсами там же где и раньше — на ваших плечах.
Здравствуйте, Mystic Artifact, Вы писали:
MA>Здравствуйте, vvv848165@ya.ru, Вы писали:
Б>>>Для таких случаев предназначен блок finally. Обычно в нем освобождают ресуры. VYR>> а не всёравно где бороду писать??? MA> Не всё равно. Конструкция try/catch/finally, или даже try/finally. Делать же catch ради высвобождения ресурсов — вредно. MA> Проблема, в том, что одни люди не понимают как работать с исключениями, а вторые — не совсем еще осознали, что GC лишь помогает, а детерминированное управление ресурсами там же где и раньше — на ваших плечах.
Да блин зацепились...
Еслиб исключений небыло а только возвращались бы коды ошибок — то было бы подругому...
и борода былабы меньше и писалась она бы в нужных местах...
Здравствуйте, vvv848165@ya.ru, Вы писали:
VYR>Да блин зацепились... VYR>Еслиб исключений небыло а только возвращались бы коды ошибок — то было бы подругому... VYR>и борода былабы меньше и писалась она бы в нужных местах...
Если бы в хроме гугл использовал исключения — он валился бы гораздо чаще и было бы исправлено больше багов. Но свидетели секты гугла и C++ такого принять не могут, и поэтому просто пишут "if (!something_) return;", что означает приблизительно следующее: если что-то пошло не так, то ну его нафиг. Пока такого стиля код находится в очистке ресурсов — все ок, но он на практике везде, а львиная доля методов не возвращает никаких ошибок, потому что иначе можно здохнуть под весом их кодов.
Вся прелесть исключений в том, что если их не использовать — то они всё равно работают.
Вся прелесть исключений в том, что обрабатывать надо только восстановимые ошибки.
Я не говорю, что они идеальны, у них есть некоторые проблемы даже в современных языках, и то это наверное не про C#. Но они явно лучше чем голые коды ошибок.
И это не повод их пихать везде где только нельзя.
Изначально, я пытался указать,что проблема не в исключениях, а что написанный код (пример), был написан неправильно и файл не закрывался в случае возникновения исключения. Решается это с помощью using.
Соответственно обе обозначенные проблемы дизайна в изначальном топике (высвобождение ресурсов и исключения) — по большому счету не релевантны.
Здравствуйте, vvv848165@ya.ru, Вы писали:
VYR>Здравствуйте, Mystic Artifact, Вы писали:
MA>>Здравствуйте, vvv848165@ya.ru, Вы писали:
Б>>>>Для таких случаев предназначен блок finally. Обычно в нем освобождают ресуры. VYR>>> а не всёравно где бороду писать??? MA>> Не всё равно. Конструкция try/catch/finally, или даже try/finally. Делать же catch ради высвобождения ресурсов — вредно. MA>> Проблема, в том, что одни люди не понимают как работать с исключениями, а вторые — не совсем еще осознали, что GC лишь помогает, а детерминированное управление ресурсами там же где и раньше — на ваших плечах. VYR>Да блин зацепились... VYR>Еслиб исключений небыло а только возвращались бы коды ошибок — то было бы подругому... VYR>и борода былабы меньше и писалась она бы в нужных местах...
Ну так и напиши обертку над System.IO которая перехватывает исключения и возвращает ошибку или результат. Вот делов-то...
Здравствуйте, Poopy Joe, Вы писали:
PJ>Ну так и напиши обертку над System.IO которая перехватывает исключения и возвращает ошибку или результат. Вот делов-то...
Тогда уж сразу вокруг нативных API.
VYR>FileStream fs — а если он нужен в качестве свойства в классе?
Тогда приплыли, ибо тогда класс становится IDisopsable и его тоже надо оборачивать в using, но главное что это касается также всех кто напрямую или косвенно содержат объект этого класса. Но, это проблема только в языках без нормального scope-based lifetime (using'и, try-with-resources, with, как видишь, проблему не решают)
Здравствуйте, vvv848165@ya.ru, Вы писали:
VYR>Да блин зацепились... VYR>Еслиб исключений небыло а только возвращались бы коды ошибок — то было бы подругому... VYR>и борода былабы меньше и писалась она бы в нужных местах...
Здравствуйте, vvv848165@ya.ru, Вы писали:
VYR>Здравствуйте, Mystic Artifact, Вы писали:
MA>> Вся прелесть исключений в том, что обрабатывать надо только восстановимые ошибки. VYR>Раскажи по подробне!
Если пользователь пытается, например, открыть файл, функция кидает исключение, пользователь видит сообщение об ошибке и исправляется. А вот Access Violation ловить не нужно.
Здравствуйте, TG, Вы писали:
TG>Здравствуйте, vvv848165@ya.ru, Вы писали:
VYR>>Да блин зацепились... VYR>>Еслиб исключений небыло а только возвращались бы коды ошибок — то было бы подругому... VYR>>и борода былабы меньше и писалась она бы в нужных местах...
TG>Про коды ошибок и исключения см. тут: https://rsdn.org/forum/philosophy/1500888.1
.
либо занимайся ООП при оработке ошибок (даже вложеную цепочку можно построить)
либо гадай на каком этапе была ошибка, что в try...catch невозможно узнать без костылей...
Здравствуйте, vvv848165@ya.ru, Вы писали:
MA>> Вся прелесть исключений в том, что обрабатывать надо только восстановимые ошибки. VYR>Раскажи по подробне!
Погугли пожалуйста, тема обсосана 100500 раз. Хотя... в разные года были разные мнения.
Если коротко и на пальцах: обрабатывать в своём коде следует только то, что твой код может (осмысленно) обработать.
(1) Например, ты пытаешься открыть файл журнала и добавить в него запись и закрыть. Но открыть файл не получилось. Данная ситуация легко ловится кэтчем по заданному типу исключению (и желательно с фильтром по коду ошибки.) Как акт по "восстановлению" — ты можешь попробовать выполнить данную операцию снова, либо записать в другой файл журнала. Это будет более-менее осмысленная обработка, и в данном случае она выполняется уровнем выше, чем реализация.
(2) Например, всё так же как выше, но получаешь ты NullReferenceException — ты его ждал? Нет. Можешь сейчас предпринять что-то полезное, кроме как телепортировать джина с дебаггером,что б пофиксил баг? Нет. Значит наш обработчик не должен это обрабатывать.
Вероятности:
(3) Например, пользователь сохраняет документ. Тут мы можем ожидать огромный спектр неизвестных ошибок. От внутренних багов до иных сбоев. Крупные проекты как правило включают связки сторонних библиотек и компонент, и реально предсказать работу сложно. Скорее всего, в такой ситуации не стоит падать при первой возможности, так у пользователя появится шанс не потерять свои последние пол часа жизни зря. Впрочем, это правило более-менее относится ко всему UI. В тоже время это относится только к тем, приложениям, которые на это рассчитаны, иначе только падать.
Инфраструктура:
(4) Все обработчики верхнего уровня служат целям подобным (3), но либо пишут в лог, либо в соотв. со своими требованиями. Они нужны и должны кэтчить всё. Когда говорят что кэтчить всё нельзя — имеют ввиду (1)/(2), но не (4).
Ну, очень много логики довольно легко строится на принципе была ошибка или нет. Как типичная реакция на нее, к примеру, запись в журнал и постановка этой задачи обратно в очередь на выполнение. Если кто-то в таком коде придерется к тосу что он ловит всё — дайте ему в рожу.