Can we write any code statement inside a Catch block of try catch in c#,
Or is there any restriction on what we cannot or should not write inside Catch block of C#?
You can't yield or await inside a catch block. So the following two won't compile:
public IEnumerable<int> SomeSequence()
{
try
{
//do something
}
catch
{
yield 1; //error
}
}
or
public async int SomeFuncAsync()
{
try
{
//do something
}
catch
{
await Task.Delay(1000); //error
}
}
You can easily work around this though:
public async int SomeFuncAsync()
{
Exception ex = null;
try
{
//do something
}
catch(Exception exc)
{
ex = exc;
}
if(ex != null) await Task.Delay(1000); // no error
}
Related
I should have a function that must return either a string of an error (through try / catch) or a different type T.
Example of such a function:
public T get()
{
T struttura;
try {
...
}
catch (Exception xcp) {
return xcp.Message;
}
...
return struttura;
}
There are ways to do this, but really consider if that's what you actually want. It is almost always better just to let the Exception bubble upwards into the calling code.
The first way is to use an out parameter.
public string get(out T result)
{
T struttura;
try{...}
catch (Exception xcp)
{
result = default(T);
return xcp.Message;
}
...
result = struttura;
return String.Empty;
}
The second way is to use a ValueTuple:
public (T, string) get()
{
T struttura;
try{...}
catch (Exception xcp){return (default(T), dexcp.Message);}
...
return (struttura, string.Empty);
}
The .net design guidelines https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/exception-throwing recommend never returning the exception as a return type. It’s always better design to throw the error and catch in the caller.
The guidelines also recommend that if you don’t want to throw the error that you can follow the TryParse pattern https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/exceptions-and-performance#try-parse-pattern. Typically you provide both methods, Get and TryGet. The presence of the Try method should indicate to callers that Get will throw exceptions but TryGet won’t. The TryGet also returns a Boolean if the operation was successful, allowing you to handle negative cases without using a try/catch block on the caller.
I suggest TryGet signature:
public bool TryGet(out T struttura) {
try {
...
struttura = ...
...
return true;
}
catch (Exception xcp){
struttura = default(T);
return false;
}
}
Usage:
if (TryGet(out var myStruct)) {
// succeeded, myStruct is returned struttura
}
else {
// failed
}
Or either do not catch exceptions at all or re-throw exception as custom one:
public T Get() {
try {
...
return struttura;
}
catch (Exception xcp) {
throw new MyException("My message", xcp);
}
}
Usage:
try {
myStruct = Get();
}
catch (MyException e) {
// Failed, e.Message for message
Console.WriteLine(e.Message);
}
Finally, you can mechanically combine value and message and return named tuple:
public (T value, string message) Get() {
try {
...
return (struttura, null);
}
catch (Exception xcp) {
return (default(T), xcp.message);
}
}
Usage:
var result = Get();
if (result.message == null) {
// succceded with result.value
}
else {
// failed with result.message
}
try
{
myInfo = getMyInfoFromAPI(); //stubbed
}
catch (JsonSerializationException exception)
{
// special handling and logging
}
catch (Exception ex)
{
// special handling and logging
}
This kind of code in my opinion is quite long and could be broken into separate functions. Is it possible to move the catches each into finally block where it can see if there is anything to catch?
try
{
myInfo = getMyInfoFromAPI(); //stubbed
}
finally {
handleJsonException();
handleException();
}
public void handleJsonException() {
catch (JsonSerializationException exception)
{
// special handling and logging
}
}
public void handleException() {
catch (Exception exception)
{
// special handling and logging
}
}
Is this possible or even good practice? The reason I'm curious if we can move the catches into new functions is the lines of code can become quite long and unreadable for one given function.
finally cannot catch exception.
I recommend to use like this.
try
{
myInfo = getMyInfoFromAPI(); //stubbed
}
catch (JsonSerializationException ex)
{
handleJsonException(ex);
}
catch (Exception ex)
{
handleException(ex);
}
public void handleJsonException(JsonSerializationException ex) {
// special handling and logging
}
public void handleException(Exception ex) {
// special handling and logging
}
The purpose of finally is not to catch exception, it will be called irrespective of Exception is thrown or not, use finally for clean-up purposes (disposing of objects).
If you want to make the catch block modular based on the Exception type then you can do something like -
try
{
// Some Code
}
catch (Exception exception)
{
if (exception is InvalidOperationException operationException)
{
MethodCall(operationException);
}
else if (exception is JsonSerializationException jsonSerializationException)
{
AnotherMethodCall(jsonSerializationException);
}
// If want to throw the exception further.
throw;
}
Is it possible to resume the execution of my Programm after the first catch even if i throwed the exception?
I made an example programm but the line where i added the exception to my List<string> has to be executed exactly after the inner and inside the outer foreach i know it would be possible if i wouldnt throw the exception but i have to do this aswell.
foreach(var x in x)
{
try
{
List<string> exs = new List<string>();
foreach(var a in b)
{
try
{
//...some code
}
catch(Exception ex)
{
throw ex;
}
finally
{
//...some code
}
}
exs.Add(ex);
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
finally
{
//...some code
}
}
Don't throw them, but collect and print them later.
List<Exception> exs = new List<Exception>();
try
{
foreach(var a in b)
{
try
{
//...some code
}
catch(Exception ex)
{
exs.Add(ex);
}
finally
{
//...some code
}
}
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
//...some code
}
exs.ForEach(ex=> Console.WriteLine(ex.ToString()));
Enforce each Inside method must have throw or enforce not use try catch block.
Below example InsideMethod2() is not implemted throw in this case when it's is calling in Main() method, should give some warning or error message saying that you must throw or should not use try catch block.
Example :
public void Main()
{
try
{
InsideMethod1();
InsideMethod2();
}
catch (System.Exception)
{
throw;
}
}
public int InsideMethod1()
{
try
{
// implementation here
}
catch (System.Exception)
{
// log
throw;
}
}
public int InsideMethod2()
{
// enforce throw or enforce not use try catch block
int a = 1, b = 0, c = 0;
try
{
c = a / b;
}
catch (System.Exception)
{
// enforce to throw
// log
}
return c;
}
Is it possible to enforce inside methods..?
I have the following methods in c#:
void Method1()
{
try
{
Method2();
}
catch(Method2Exception ex)
{
//Log error
}
}
void Method2()
{
if(error)
{
throw(new Method2Exception("error"));
}
//Do something and call method3
try
{
Method3();
}
catch(Method3Exception)
{
//??
}
}
void Method3()
{
//Do something
if(error)
{
throw(new Method3Exception("error"));
}
}
Method3 its gonna be call by different methods and it returns Method3Exception and I need rethrow the exception from Method2 to Method1 but I don't want catch Method3Exception on Method1. what's the best way to do that?
Any suggestions
The term (re)throw usally refer to throwing the exception back to the caller preserving the stack trace (which contains where the exception exactly occurred). This can be done using throw; without specifying the exception operand contrary to throw ex:
try
{
Method3();
}
catch(Method3Exception)
{
throw;
}
However, if you're just going to add a throw with nothing before it in that method. It is useless, just remove the try..catch and the exception is going to propagate to the caller which is the default behavior.
Docs:
A throw statement can be used in a catch block to re-throw the
exception that the catch block caught. In this case, the throw
statement does not take an exception operand.
Alternative way to re-throwing the exception (using throw; as described in other answers) is to wrap the exception in inner exception. As described in MSDN, all custom exceptions should have at least four constructors, and one of them is
public InvalidDepartmentException(string message, System.Exception inner) : base(message, inner) { }
So if all your custom exceptions are like this, you could wrap the exception from Method3 as inner exception:
void Method2()
{
if(error)
{
throw(new Method2Exception("error"));
}
//Do something and call method3
try
{
Method3();
}
catch(Method3Exception exc)
{
throw new Method2Exception("error", exc); // exc is passed as inner exception
}
}
Then if you want to inspect the inner exception in Method1, you can use property InnerException:
void Method1()
{
try
{
Method2();
}
catch(Method2Exception ex)
{
if(ex.InnerException != null)
{
var message = ex.InnerException.Message;
// Do what you need with the message
}
}
}
In Method2, you can throw a new Method2Exception with the existing Method3Exception as its InnerException:
try
{
Method3();
}
catch(Method3Exception method3Exception)
{
throw new Method2Exception("Message", method3Exception);
}
Then you can catch the Method2Exception above:
try
{
Method2();
}
catch(Method2Exception ex)
{
//Log error
}
Exceptions are bubbles up by default. For example,
void FirstMethod()
{
int a = 0;
int b = 10;
int c = b / a;
}
void SecondMethod()
{
FirstMethod();
}
void ThirdMethod()
{
SecondMethod();
}
void FourthMethod()
{
try
{
ThirdMethod();
}
catch (DivideByZeroException ex)
{
// Handle error
}
}
The exception will occur in FirstMethod and it will go upwards and will be cought at ForurthMethod. If you want to log the exception at ThirdMethod for example, but still want your exception to be handled at FourthMethod then you have to options:
First option:
void ThirdMethod()
{
try
{
SecondMethod();
}
catch (Exception ex)
{
// Log the error
throw; // Throw exception without affecting StackTrace
}
}
Second option:
After C# 6.0 you can do this with ease by using exception filters. Create a logger method which returns false.
bool Log(Exception ex)
{
// Log the error
return false;
}
Add exception filter in third method:
void ThirdMethod()
{
try
{
SecondMethod();
}
catch (Exception ex) when(Log(ex))
{
// Debugger won't reach here
}
}