2009-07-24 3 views
23

Одна вещь, которая прослушивала меня с обработкой исключений, исходящей от Python до C#, заключается в том, что в C# не существует способа указать условие else. Например, в Python я мог бы написать что-то вроде этого (примечание, это просто пример, я не спрашиваю, что это лучший способ, чтобы прочитать файл.):C# try-catch-else

try 
{ 
    reader = new StreamReader(path); 
} 
catch (Exception) 
{ 
    // Uh oh something went wrong with opening the file for reading 
} 
else 
{ 
    string line = reader.ReadLine(); 
    char character = line[30]; 
} 

Из того, что я видел в большинстве C# код люди будут просто написать следующее:

try 
{ 
    reader = new StreamReader(path); 
    string line = reader.ReadLine(); 
    char character = line[30]; 
} 
catch (Exception) 
{ 
    // Uh oh something went wrong, but where? 
} 

Проблема в том, что я не хочу, чтобы поймать из исключения диапазона, поступающего из того, что первая строка в файле не может содержать более 30 персонажи. Я хочу только перехватывать исключения, связанные с чтением файлового потока. Есть ли подобная конструкция, которую я могу использовать в C# для достижения того же?

+3

Я удивлен, что никто не придумал ответ с указанием goto! –

+11

catching general Исключения никогда не являются хорошей идеей, но вы можете указать, какие типы исключений пойманы. –

+2

Я предполагаю, что я не уточнил исходный вопрос, но то, что я получаю, - это то, что я не хочу маскировать ошибки в разделе try {}, улавливая их и позволяя программе продолжить свой путь. Я бы предпочел, чтобы он разбился, чтобы сразу исправить ошибку. Хотя он также способен обрабатывать случаи, которые не поддаются контролю (т. Е. Файл отсутствует или не имеет к нему доступа, поскольку он находится на сетевом диске и т. Д.).Большинство решений предлагают ловить IOException, но что, если StreamReader выбрасывает какой-либо другой тип исключения, который я, возможно, не ожидал? –

ответ

43

Поймайте конкретный класс исключений

try 
{ 
    reader = new StreamReader(path); 
    string line = reader.ReadLine(); 
    char character = line[30]; 
} 
catch (IOException ex) 
{ 
    // Uh oh something went wrong with I/O 
} 
catch (Exception ex) 
{ 
    // Uh oh something else went wrong 
    throw; // unless you're very sure what you're doing here. 
} 

Второй улов не является обязательным, конечно. И поскольку вы не знаете, что произошло, проглатывание этого наиболее общего исключения очень опасно.

+3

Я бы предпочел отдельно попробовать {...} catch (исключение) {...} вокруг чтения. Исключая исключения, вы никогда не знаете, что еще может сделать читатель, кроме IOException - сейчас или в будущем. –

+0

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

+0

Tiberiu, «вы никогда не знаете, что еще» идет с IndexOutOfRange из char [30] и т. Д. Не нужно рассматривать ReadLine по-разному, если нет веской причины. Но поймать «остаток» может произойти выше. –

8

Вы можете сделать это:

try 
{ 
    reader = new StreamReader(path); 
} 
catch (Exception) 
{ 
    // Uh oh something went wrong with opening the file for reading 
} 

string line = reader.ReadLine(); 
char character = line[30]; 

Но, конечно же, вам придется установить reader в правильное состояние или return из метода.

+0

Ты избил меня. – Tundey

+0

Это только улавливает ошибки при открытии считывателя, а не в фактическом чтении. –

+1

@Henk True, так же как и исходный код Python. –

4

Исключения используются по-разному в .NET; они предназначены исключительно для исключительных условий.

На самом деле, вы не должны поймать исключение, если не знаете, что это значит, и могут на самом деле сделать что-то о нем.

+4

Этот совет применяется так же сильно, как и для Python как .NET. –

+0

Downvoter: Почему? –

+5

Это не отвечает на вопрос. –

2

У вас может быть несколько предложений catch, каждое из которых зависит от типа исключения, которое вы хотите поймать. Итак, если вы хотите, чтобы поймать IOExceptions, то вы могли бы изменить положение поймать на это:

try 
{ 
    reader = new StreamReader(path); 
    string line = reader.ReadLine(); 
    char character = line[30]; 
} 
catch (IOException) 
{  
} 

ничего, кроме IOException затем распространяются вверх по стеку вызовов. Если вы хотите также обрабатывать другие исключения, вы можете добавить несколько исключений, но вы должны убедиться, что они добавлены в большинстве случаев для большинства общих заказов. Например:

try 
{ 
    reader = new StreamReader(path); 
    string line = reader.ReadLine(); 
    char character = line[30]; 
} 
catch (IOException) 
{  
} 
catch (Exception) 
{ 
} 
6

Поймать более конкретные исключения.

try { 
    reader = new StreamReader(path); 
    string line = reader.ReadLine(); 
    char character = line[30]; 
} 
catch(FileNotFoundException e) { 
    // thrown by StreamReader constructor 
} 
catch(DirectoryNotFoundException e) { 
    // thrown by StreamReader constructor 
} 
catch(IOException e) { 
    // some other fatal IO error occured 
} 

Далее, в общем, обрабатывать наиболее конкретное исключение можно и избежать обработки базы System.Exception.

+0

@Martin Liversage: Вы правы. Благодарю. – jason

2

Более идиоматически, вы бы нанять using заявление, чтобы отделить операции открытия файла с работы, проделанной на данных, которые он содержит (и включать автоматическую очистку на выходе)

try { 
    using (reader = new StreamReader(path)) 
    { 
    DoSomethingWith(reader); 
    } 
} 
catch(IOException ex) 
{ 
    // Log ex here 
} 

Это также лучше чтобы избежать всех возможных исключений - например, тех, кто говорит вам, что время выполнения истекает.

+0

Мартин Шербурн спрашивал, как писать try/catch/else в C#, а не как правильно писать файловые открыватели. –

2

Вы можете вложить свои заявления попробовать тоже

1

Есть ли подобная конструкция я могу использовать в C# для того чтобы достигнуть то же самое?

No.

Оберните указательный аксессор с «если» заявление, которое является лучшим решением в вашем случае в случае выполнения и читаемость.

if (line.length > 30) { 
    char character = line [30]; 
} 
10

Вы могли бы написать это нравится:

bool success = false; 
try { 
    reader = new StreamReader(path); 
    success = true; 
} 
catch(Exception) { 
    // Uh oh something went wrong with opening the file for reading 
} 
finally { 
    if(success) { 
     string line = reader.ReadLine();  
     char character = line[30]; 
    } 
} 
+6

Зачем ставить его в блок finally? –

0

Я взял на себя смелость, чтобы превратить ваш код немного, чтобы продемонстрировать несколько важных моментов.

Конструкция using используется, чтобы открыть файл. Если вы выбрали исключение, вам придется не забудьте закрыть файл, даже если вы не поймаете исключение. Это можно сделать, используя конструкцию try { } catch() { } finally { }, но для этого намного лучше подходит директива using. Это гарантирует, что, когда объем блока using заканчивается, переменная, созданная внутри, будет удалена. Для файла это означает, что он будет закрыт.

Изучив документацию для конструктора StreamReader и метод ReadLine, вы можете увидеть, какие исключения вы можете ожидать. Затем вы можете поймать тех, кого вы найдете. Обратите внимание, что зарегистрированный список исключений не всегда завершен.

// May throw FileNotFoundException, DirectoryNotFoundException, 
// IOException and more. 
try { 
    using (StreamReader streamReader = new StreamReader(path)) { 
    try { 
     String line; 
     // May throw IOException. 
     while ((line = streamReader.ReadLine()) != null) { 
     // May throw IndexOutOfRangeException. 
     Char c = line[30]; 
     Console.WriteLine(c); 
     } 
    } 
    catch (IOException ex) { 
     Console.WriteLine("Error reading file: " + ex.Message); 
    } 
    } 
} 
catch (FileNotFoundException ex) { 
    Console.WriteLine("File does not exists: " + ex.Message); 
} 
catch (DirectoryNotFoundException ex) { 
    Console.WriteLine("Invalid path: " + ex.Message); 
} 
catch (IOException ex) { 
    Console.WriteLine("Error reading file: " + ex.Message); 
} 
1

Осмотрев другие предложенные решения, вот мой подход:

try { 
    reader = new StreamReader(path); 
} 
catch(Exception ex) { 
    // Uh oh something went wrong with opening the file stream 
    MyOpeningFileStreamException newEx = new MyOpeningFileStreamException(); 
    newEx.InnerException = ex; 
    throw(newEx); 
} 
    string line = reader.ReadLine(); 
    char character = line[30]; 

Конечно, делать это имеет смысл, только если вы заинтересованы в любых исключения, брошенного путем открытия потока файлов (в качестве примера) от от всех других исключений в приложении. На каком-то более высоком уровне приложения вы можете обращаться с MyOpeningFileStreamException по своему усмотрению.

Из непроверенных исключений, вы никогда не можете быть 100% уверены, что ловить только IOException из всего блока кода будет достаточно - StreamReader может принять решение бросить какой-то другой тип исключения тоже сейчас или в будущем.

0

Похоже, вы хотите сделать вторую вещь, только если первое удалось. И, возможно, ловить разные классы исключений не подходит, например, если оба оператора могут выдать один и тот же класс исключения.

try 
{ 
    reader1 = new StreamReader(path1); 
    // if we got this far, path 1 succeded, so try path2 
    try 
    { 
     reader2 = new StreamReader(path2); 

    } 
    catch (OIException ex) 
    { 
     // Uh oh something went wrong with opening the file2 for reading 
     // Nevertheless, have a look at file1. Its fine! 
    } 
} 
catch (OIException ex) 
{ 
    // Uh oh something went wrong with opening the file1 for reading. 
    // So I didn't even try to open file2 
} 
Смежные вопросы