I'm deliberately throwing an exception for a particular scenario, but I would implicitly like to get the error message in string format. I'm aware that one of the overloads for the following exception is string message, but how do I access that string?
Here is the relevant snippet:
string errMsg;
private void Compress()
{
if (sourcePath.EndsWith(".zip"))
{
throw new FileLoadException
("File already compressed. Unzip the file and try again.");
errMsg = //I want the above string here
}
}
Do you mean this:?
try
{
throw new FileLoadException
("File already compressed. Unzip the file and try again.");
}
catch (Exception ex)
{
errMsg = ex.GetBaseException().Message;
}
You can't access the string THERE I'll explain a bit there:
string errMsg;
private void Compress()
{
if (sourcePath.EndsWith(".zip"))
{
throw new FileLoadException
("File already compressed. Unzip the file and try again.");
// The following line is unreachable as the throw ends the function and gets the exception to the calling function as there is no try catch block to catch the exception.
errMsg = //I want the above string here
}
}
A possibility would be to try/catch the exception in the method where you want to set the variable:
private void Compress()
{
if (sourcePath.EndsWith(".zip"))
{
try
{
throw new FileLoadException
("File already compressed. Unzip the file and try again.");
}
catch (Exception e)
{
errMsg = e.Message;
}
}
}
Or to catch the exception in the calling method instead:
try
{
Compress();
}
catch (Exception e)
{
}
regardless of method used the e.Message gives you the message of the exception as a string.
There is no point to try catch the exception and set the message. Unless you re-throw it
try
{
throw new FileLoadException("File already compressed. Unzip the file and try again.");
}
catch (Exception ex)
{
errMsg = ex.GetBaseException().Message;
throw;
}
I would rather do this
private void Compress()
{
if (sourcePath.EndsWith(".zip"))
{
errMsg = "File already compressed. Unzip the file and try again.";
return;
}
}
Not sure I 100% understand but if you want the message from that exception you can catch it and examine the Exception.Message
try
{
throw new FileLoadException("Custom error string");
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
here should be an solution for you :)
if (sourcePath.EndsWith(".zip"))
{
FileLoadException ex = new FileLoadException("File already compressed. Unzip the file and try again.");
errMsg = ex.ToString();
}
Console.WriteLine(errMsg);
To throw the exception that you made I would do soemthing like this
static string sourcePath = "test.zip"; //hardcoded file
static string errMsg; //the error string
private static void Compress()
{
try
{
if (!sourcePath.EndsWith(".zip"))
{
Console.WriteLine("File doesn't end with zip so it can be compressed"); //if it does not end with zip its rdy for compressing and here you can indput your code to compress
}
else
{
throw new Exception(); //instead of using try catch you can also generate the code in here instead of throwing an exception.
//when throwing a new exception you make it stop the if setting and jump into the catch if you use break it wont enter the catch but instead it will just jump over it.
}
}
catch
{
//Here it will generate the custom exception you wanted and put it inside the errMsg
errMsg = new FileLoadException("File already compressed. Unzip the file and try again.").ToString();
Console.WriteLine(errMsg);
}
ofc this is made in console that is why I use the console.writeline you can just change those out
Related
I want to keep logs exception from catch and send to database or text file ?
try
{
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
thank you
This will create a text file or append the txt if it is already present with the date and time of the exception thrown. I hope this is what your were looking for.
catch(Exception Ex)
{
StreamWriter sw = null;
String Logfile = "C:\ExceptionLog.txt";
if (!System.IO.File.Exists(LogFile))
{
sw = File.CreateText(LogFile);
sw.WriteLine(String.Format("Exception\t DateTime"));
}
else
{
sw = File.AppendText(#"C:\ExceptionLog.txt");
}
sw.WriteLine(String.Format("{0}\t {1}", Ex,
DateTime.Now.ToString("MM/dd/yyy HH:mm:ss"));
sw.Close();
}
Simply, create object of your database context if you are using Entity
framework and insert it in your table(e.g. a table containing(id,
Exception Name, innermessage, error number, CreatedDateTime, etc)).
catch (Exception ex)
{
DatabaseEntity DbObj = new DatabaseEntity();
ExceptionTable ExObj = new ExceptionTable();
ExObj.ExceptionName = ex.Message;
ExObj.InnerException = ex.InnerException;
.....
//Code according to your need
.....
DbObj.ExceptionTable.Add(ExObj);
DbObj.SaveChanges();
MessageBox.Show(ex.Message);
}
you may follow this
How to Log Exception in a file?,
this may help you
I am pretty new to programming and am trying to figure out how to to catch the error "FileNotFoundException." My code is suppose to search for the existing text document (from what is typed into the text box)and load it to my listbox1. I got this problem solved. However, a new problem has arisen! If the user inputs the wrong name/numbers it just crashes the application with the error that it couldn't find the file. Is there any way to get the program to display an error message "File not found." or simply not crash the entire program? Thanks in advance!
private void btnEnter_Click(object sender, EventArgs e)
{
FileInfo file = new FileInfo(txtExisting.Text + ".txt");
StreamReader stRead = file.OpenText();
while (!stRead.EndOfStream)
{
listBox1.Items.Add(stRead.ReadLine());
}
}
You should use a try-catch statement to handle exceptions.
private void btnEnter_Click(object sender, EventArgs args)
{
try
{
FileInfo file = new FileInfo(txtExisting.Text + ".txt");
StreamReader stRead = file.OpenText();
while (!stRead.EndOfStream)
{
listBox1.Items.Add(stRead.ReadLine());
}
}
catch (FileNotFoundException e)
{
// FileNotFoundExceptions are handled here.
}
}
Basically, the code in the try block will be executed as it would normally be but if an error should arise the catch block will be executed, in particular:
When an exception is thrown, the common language runtime (CLR) looks for the catch statement that handles this exception.
This means that a try-catch statement can have multiple catch blocks if you expect to encounter different types of exceptions so they can be handled accordingly.
More information can be found here.
As for UX, it would be nice to communicate to the user that something went wrong by displaying a message.
Just add a try/catch block with your code in the btnEnter_Click function like this:
try
{
//your code here
}
catch (FileNotFoundException ex)
{
MessageBox.Show(ex.Message);//if you want to show the exception message
}
catch (Exception ex1)
{
/* Exceptions other than the above will be handled in this section,
this should be used when you are not aware the type of exception
can occur in your code for a safe side*/
}
Using a try/catch statement :
private void btnEnter_Click(object sender, EventArgs e)
{
try
{
FileInfo file = new FileInfo(txtExisting.Text + ".txt");
StreamReader stRead = file.OpenText();
while (!stRead.EndOfStream)
{
listBox1.Items.Add(stRead.ReadLine());
}
}
catch (FileNotFoundException ex)
{
// Handle exception
}
}
Use System.IO.File.Exist("path\\File.extension");
File.Exists / MSDN
It will return a Boolean value, true for File Found and false for File Not Found.
Use the try/catch statements when you don't WHAT could cause a problem.
Example:
private void btnEnter_Click(object sender, EventArgs e)
{
if(!System.IO.File.Exists(txtExisting.Text + ".txt")
{
MessageBox.Show("File not found");
return;
}
FileInfo file = new FileInfo(txtExisting.Text + ".txt");
StreamReader stRead = file.OpenText();
while (!stRead.EndOfStream)
{
listBox1.Items.Add(stRead.ReadLine());
}
}
FileInfo file = new FileInfo(txtExisting.Text + ".txt");
if (!File.Exists(file.FullName))
{
Console.WriteLine("File Not Found!");
}
else
{
StreamReader stRead = file.OpenText();
while (!stRead.EndOfStream)
{
lenter code hereistBox1.Items.Add(stRead.ReadLine());
}
}
If a finally block throws an exception, what exactly happens?
Specifically, what happens if the exception is thrown midway through a finally block. Do the rest of statements (after) in this block get invoked?
I am aware that exceptions will propagate upwards.
If a finally block throws an exception what exactly happens ?
That exception propagates out and up, and will (can) be handled at a higher level.
Your finally block will not be completed beyond the point where the exception is thrown.
If the finally block was executing during the handling of an earlier exception then that first exception is lost.
C# 4 Language Specification ยง 8.9.5: If the finally block throws another exception, processing of the current exception is terminated.
For questions like these I usually open up an empty console application project in Visual Studio and write a small sample program:
using System;
class Program
{
static void Main(string[] args)
{
try
{
try
{
throw new Exception("exception thrown from try block");
}
catch (Exception ex)
{
Console.WriteLine("Inner catch block handling {0}.", ex.Message);
throw;
}
finally
{
Console.WriteLine("Inner finally block");
throw new Exception("exception thrown from finally block");
Console.WriteLine("This line is never reached");
}
}
catch (Exception ex)
{
Console.WriteLine("Outer catch block handling {0}.", ex.Message);
}
finally
{
Console.WriteLine("Outer finally block");
}
}
}
When you run the program you will see the exact order in which catch and finally blocks are executed. Please note that code in the finally block after the exception is being thrown will not be executed (in fact, in this sample program Visual Studio will even warn you that it has detected unreachable code):
Inner catch block handling exception thrown from try block.
Inner finally block
Outer catch block handling exception thrown from finally block.
Outer finally block
Additional Remark
As Michael Damatov pointed out, an exception from the try block will be "eaten" if you don't handle it in an (inner) catch block. In fact, in the example above the re-thrown exception does not appear in the outer catch block. To make that even more clear look at the following slightly modified sample:
using System;
class Program
{
static void Main(string[] args)
{
try
{
try
{
throw new Exception("exception thrown from try block");
}
finally
{
Console.WriteLine("Inner finally block");
throw new Exception("exception thrown from finally block");
Console.WriteLine("This line is never reached");
}
}
catch (Exception ex)
{
Console.WriteLine("Outer catch block handling {0}.", ex.Message);
}
finally
{
Console.WriteLine("Outer finally block");
}
}
}
As you can see from the output the inner exception is "lost" (i.e. ignored):
Inner finally block
Outer catch block handling exception thrown from finally block.
Outer finally block
If there is an exception pending (when the try block has a finally but no catch), the new exception replaces that one.
If there is no exception pending, it works just as throwing an exception outside the finally block.
Quick (and rather obvious) snippet to save "original exception" (thrown in try block) and sacrifice "finally exception" (thrown in finally block), in case original one is more important for you:
try
{
throw new Exception("Original Exception");
}
finally
{
try
{
throw new Exception("Finally Exception");
}
catch
{ }
}
When code above is executed, "Original Exception" propagates up the call stack, and "Finally Exception" is lost.
The exception is propagated.
Throwing an exception while another exception is active will result in the first exception getting replaced by the second (later) exception.
Here is some code that illustrates what happens:
public static void Main(string[] args)
{
try
{
try
{
throw new Exception("first exception");
}
finally
{
//try
{
throw new Exception("second exception");
}
//catch (Exception)
{
//throw;
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
Run the code and you will see "second exception"
Uncomment the try and catch statements and you will see "first exception"
Also uncomment the throw; statement and you will see "second exception" again.
Some months ago i also faced something like this,
private void RaiseException(String errorMessage)
{
throw new Exception(errorMessage);
}
private void DoTaskForFinally()
{
RaiseException("Error for finally");
}
private void DoTaskForCatch()
{
RaiseException("Error for catch");
}
private void DoTaskForTry()
{
RaiseException("Error for try");
}
try
{
/*lacks the exception*/
DoTaskForTry();
}
catch (Exception exception)
{
/*lacks the exception*/
DoTaskForCatch();
}
finally
{
/*the result exception*/
DoTaskForFinally();
}
To solve such problem i made a utility class like
class ProcessHandler : Exception
{
private enum ProcessType
{
Try,
Catch,
Finally,
}
private Boolean _hasException;
private Boolean _hasTryException;
private Boolean _hasCatchException;
private Boolean _hasFinnallyException;
public Boolean HasException { get { return _hasException; } }
public Boolean HasTryException { get { return _hasTryException; } }
public Boolean HasCatchException { get { return _hasCatchException; } }
public Boolean HasFinnallyException { get { return _hasFinnallyException; } }
public Dictionary<String, Exception> Exceptions { get; private set; }
public readonly Action TryAction;
public readonly Action CatchAction;
public readonly Action FinallyAction;
public ProcessHandler(Action tryAction = null, Action catchAction = null, Action finallyAction = null)
{
TryAction = tryAction;
CatchAction = catchAction;
FinallyAction = finallyAction;
_hasException = false;
_hasTryException = false;
_hasCatchException = false;
_hasFinnallyException = false;
Exceptions = new Dictionary<string, Exception>();
}
private void Invoke(Action action, ref Boolean isError, ProcessType processType)
{
try
{
action.Invoke();
}
catch (Exception exception)
{
_hasException = true;
isError = true;
Exceptions.Add(processType.ToString(), exception);
}
}
private void InvokeTryAction()
{
if (TryAction == null)
{
return;
}
Invoke(TryAction, ref _hasTryException, ProcessType.Try);
}
private void InvokeCatchAction()
{
if (CatchAction == null)
{
return;
}
Invoke(TryAction, ref _hasCatchException, ProcessType.Catch);
}
private void InvokeFinallyAction()
{
if (FinallyAction == null)
{
return;
}
Invoke(TryAction, ref _hasFinnallyException, ProcessType.Finally);
}
public void InvokeActions()
{
InvokeTryAction();
if (HasTryException)
{
InvokeCatchAction();
}
InvokeFinallyAction();
if (HasException)
{
throw this;
}
}
}
And used like this
try
{
ProcessHandler handler = new ProcessHandler(DoTaskForTry, DoTaskForCatch, DoTaskForFinally);
handler.InvokeActions();
}
catch (Exception exception)
{
var processError = exception as ProcessHandler;
/*this exception contains all exceptions*/
throw new Exception("Error to Process Actions", exception);
}
but if you want to use paramaters and return types that's an other story
The exception propagates up, and should be handled at a higher level. If the exception is not handled at the higher level, the application crashes. The "finally" block execution stops at the point where the exception is thrown.
Irrespective of whether there is an exception or not "finally" block is guaranteed to execute.
If the "finally" block is being executed after an exception has occurred in the try block,
and if that exception is not handled
and if the finally block throws an exception
Then the original exception that occurred in the try block is lost.
public class Exception
{
public static void Main()
{
try
{
SomeMethod();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static void SomeMethod()
{
try
{
// This exception will be lost
throw new Exception("Exception in try block");
}
finally
{
throw new Exception("Exception in finally block");
}
}
}
Great article for Details
I had to do this for catching an error trying to close a stream that was never opened because of an exception.
errorMessage = string.Empty;
try
{
byte[] requestBytes = System.Text.Encoding.ASCII.GetBytes(xmlFileContent);
webRequest = WebRequest.Create(url);
webRequest.Method = "POST";
webRequest.ContentType = "text/xml;charset=utf-8";
webRequest.ContentLength = requestBytes.Length;
//send the request
using (var sw = webRequest.GetRequestStream())
{
sw.Write(requestBytes, 0, requestBytes.Length);
}
//get the response
webResponse = webRequest.GetResponse();
using (var sr = new StreamReader(webResponse.GetResponseStream()))
{
returnVal = sr.ReadToEnd();
sr.Close();
}
}
catch (Exception ex)
{
errorMessage = ex.ToString();
}
finally
{
try
{
if (webRequest.GetRequestStream() != null)
webRequest.GetRequestStream().Close();
if (webResponse.GetResponseStream() != null)
webResponse.GetResponseStream().Close();
}
catch (Exception exw)
{
errorMessage = exw.ToString();
}
}
if the webRequest was created but a connection error happened during the
using (var sw = webRequest.GetRequestStream())
then the finally would catch an exception trying to close up connections it thought was open because the webRequest had been created.
If the finally didnt have a try-catch inside, this code would cause an unhandled exception while cleaning up the webRequest
if (webRequest.GetRequestStream() != null)
from there the code would exit without properly handling the error that happened and therefore causing issues for the calling method.
Hope this helps as an example
public void MyMethod()
{
try
{
}
catch{}
finally
{
CodeA
}
CodeB
}
The way the exceptions thrown by CodeA and CodeB are handled is the same.
An exception thrown in a finally block has nothing special, treat it as the exception throw by code B.
It throws an exception ;) You can catch that exception in some other catch clause.
Is it possible to return a bool and also rethrow an exception within the same method? Ive tried with the following code and it keeps saying that unreachable code is detected or that i cant exit the finally block.
public bool AccessToFile(string filePath)
{
FileStream source = null;
try
{
source = File.OpenRead(filePath);
source.Close();
return true;
}
catch (UnauthorizedAccessException e)
{
string unAuthorizedStatus = "User does not have sufficient access privileges to open the file: \n\r" + filePath;
unAuthorizedStatus += e.Message;
MessageBox.Show(unAuthorizedStatus, "Error Message:");
throw;
}
catch (Exception e)
{
string generalStatus = null;
if (filePath == null)
{
generalStatus = "General error: \n\r";
}
else
{
generalStatus = filePath + " failed. \n\r";
generalStatus += e.Message;
}
MessageBox.Show(generalStatus, "Error Message:");
throw;
}
finally
{
if (source != null)
{
source.Dispose();
}
}
}
Once you throw an exception, processing in your current method finishes and the exception works up the call stack. Either handle your exceptions locally and then return your boolean, or throw them and let them bubble up and handle them at the front end.
One thing that has bugged me with exception handling coming from Python to C# is that in C# there doesn't appear to be any way of specifying an else clause. For example, in Python I could write something like this (Note, this is just an example. I'm not asking what is the best way to read a file):
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];
}
From what I have seen in most C# code people would just write the following:
try
{
reader = new StreamReader(path);
string line = reader.ReadLine();
char character = line[30];
}
catch (Exception)
{
// Uh oh something went wrong, but where?
}
The trouble with this is that I don't want to catch out of range exception coming from the fact that the first line in the file may not contain more than 30 characters. I only want to catch exceptions relating to the reading of the file stream. Is there any similar construct I can use in C# to achieve the same thing?
Catch a specific class of exceptions
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.
}
The second catch is optional, of course. And since you don't know what happened, swallowing this most general exception is very dangerous.
You could write it like:
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];
}
}
You can do this:
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];
But of course, you will have to set reader into a correct state or return out of the method.
Catch more specific exceptions.
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
}
Further, in general, handle the most specific exception possible and avoid handling the base System.Exception.
You can nest your try statements, too
Exceptions are used differently in .NET; they are for exceptional conditions only.
In fact, you should not catch an exception unless you know what it means, and can actually do something about it.
You can have multiple catch clauses, each specific to the type of exception you wish to catch. So, if you only want to catch IOExceptions, then you could change your catch clause to this:
try
{
reader = new StreamReader(path);
string line = reader.ReadLine();
char character = line[30];
}
catch (IOException)
{
}
Anything other than an IOException would then propagate up the call stack. If you want to also handle other exceptions, then you can add multiple exception clauses, but you must ensure they are added in most specific to most generic order. For example:
try
{
reader = new StreamReader(path);
string line = reader.ReadLine();
char character = line[30];
}
catch (IOException)
{
}
catch (Exception)
{
}
More idiomatically, you would employ the using statement to separate the file-open operation from the work done on the data it contains (and include automatic clean-up on exit)
try {
using (reader = new StreamReader(path))
{
DoSomethingWith(reader);
}
}
catch(IOException ex)
{
// Log ex here
}
It is also best to avoid catching every possible exception -- like the ones telling you that the runtime is about to expire.
Is there any similar construct I can use in C#
to acheive the same thing?
No.
Wrap your index accessor with an "if" statement which is the best solution in your case in case of performance and readability.
if (line.length > 30) {
char character = line [30];
}
After seeing the other suggested solutions, here is my approach:
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];
Of course, doing this makes sense only if you are interested in any exceptions thrown by opening the file stream (as an example here) apart from all other exceptions in the application. At some higher level of the application, you then get to handle your MyOpeningFileStreamException as you see fit.
Because of unchecked exceptions, you can never be 100% certain that catching only IOException out of the entire code block will be enough -- the StreamReader can decide to throw some other type of exception too, now or in the future.
You can do something similar like this:
bool passed = true;
try
{
reader = new StreamReader(path);
}
catch (Exception)
{
passed = false;
}
if (passed)
{
// code that executes if the try catch block didnt catch any exception
}
I have taken the liberty to transform your code a bit to demonstrate a few important points.
The using construct is used to open the file. If an exception is thrown you will have to remember to close the file even if you don't catch the exception. This can be done using a try { } catch () { } finally { } construct, but the using directive is much better for this. It guarantees that when the scope of the using block ends the variable created inside will be disposed. For a file it means it will be closed.
By studying the documentation for the StreamReader constructor and ReadLine method you can see which exceptions you may expect to be thrown. You can then catch those you finde appropriate. Note that the documented list of exceptions not always is complete.
// 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);
}
Sounds like you want to do the second thing only if the first thing succeeded. And maybe catching different classes of exception is not appropriate, for example if both statements could throw the same class of exception.
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
}
There might not be any native support for try { ... } catch { ... } else { ... } in C#, but if you are willing to shoulder the overhead of using a workaround, then the example shown below might be appealing:
using System;
public class Test
{
public static void Main()
{
Example("ksEE5A.exe");
}
public static char Example(string path) {
var reader = default(System.IO.StreamReader);
var line = default(string);
var character = default(char);
TryElse(
delegate {
Console.WriteLine("Trying to open StreamReader ...");
reader = new System.IO.StreamReader(path);
},
delegate {
Console.WriteLine("Success!");
line = reader.ReadLine();
character = line[30];
},
null,
new Case(typeof(NullReferenceException), error => {
Console.WriteLine("Something was null and should not have been.");
Console.WriteLine("The line variable could not cause this error.");
}),
new Case(typeof(System.IO.FileNotFoundException), error => {
Console.WriteLine("File could not be found:");
Console.WriteLine(path);
}),
new Case(typeof(Exception), error => {
Console.WriteLine("There was an error:");
Console.WriteLine(error);
}));
return character;
}
public static void TryElse(Action pyTry, Action pyElse, Action pyFinally, params Case[] pyExcept) {
if (pyElse != null && pyExcept.Length < 1) {
throw new ArgumentException(#"there must be exception handlers if else is specified", nameof(pyExcept));
}
var doElse = false;
var savedError = default(Exception);
try {
try {
pyTry();
doElse = true;
} catch (Exception error) {
savedError = error;
foreach (var handler in pyExcept) {
if (handler.IsMatch(error)) {
handler.Process(error);
savedError = null;
break;
}
}
}
if (doElse) {
pyElse();
}
} catch (Exception error) {
savedError = error;
}
pyFinally?.Invoke();
if (savedError != null) {
throw savedError;
}
}
}
public class Case {
private Type ExceptionType { get; }
public Action<Exception> Process { get; }
private Func<Exception, bool> When { get; }
public Case(Type exceptionType, Action<Exception> handler, Func<Exception, bool> when = null) {
if (!typeof(Exception).IsAssignableFrom(exceptionType)) {
throw new ArgumentException(#"exceptionType must be a type of exception", nameof(exceptionType));
}
this.ExceptionType = exceptionType;
this.Process = handler;
this.When = when;
}
public bool IsMatch(Exception error) {
return this.ExceptionType.IsInstanceOfType(error) && (this.When?.Invoke(error) ?? true);
}
}
If you happen to be in a loop, then you can put a continue statement in the catch blocks. This will cause the remaining code of that block to be skipped.
If you are not in a loop, then there is no need to catch the exception at this level. Let it propagate up the call stack to a catch block that knows what to do with it. You do this by eliminating the entire try/catch framework at the current level.
I like try/except/else in Python too, and maybe they will get added to C# some day (just like multiple return values were). But if you think about exceptions a little differently, else blocks are not strictly necessary.