Creating Custom Exceptions C# with Example



Creating Custom Exceptions C# with Example

You are allowed to implement custom exceptions that can be thrown just like any other exception. This makes 
sense when you want to make your exceptions distinguishable from other errors during runtime. 
In this example we will create a custom exception for clear handling of problems the application may have while 
parsing a complex input. 
Creating Custom Exception Class 
To create a custom exception create a sub-class of Exception: 
public class ParserException : Exception 
{ 
public ParserException() : 
base("The parsing went wrong and we have no additional information.") { } 
} 
Custom exception become very useful when you want to provide additional information to the catcher: 
public class ParserException : Exception 
{ 
public ParserException(string fileName, int lineNumber) : 
base($"Parser error in {fileName}:{lineNumber}") 
{ 
FileName = fileName; 
LineNumber = lineNumber; 
} 
public string FileName {get; private set;} 
public int LineNumber {get; private set;} 
} 
Now, when you catch(ParserException x) you will have additional semantics to fine-tune exception handling. 
Custom classes can implement the following features to support additional scenarios. 
re-throwing 
During the parsing process, the original exception is still of interest. In this example it is a FormatException because 
the code attempts to parse a piece of string, which is expected to be a number. In this case the custom exception 
should support the inclusion of the 'InnerException': 
//new constructor: 
ParserException(string msg, Exception inner) : base(msg, inner) { 
} 
serialization 
In some cases your exceptions may have to cross AppDomain boundaries. This is the case if your parser is running 
in its own AppDomain to support hot reloading of new parser configurations. In Visual Studio, you can use 
Exception template to generate code like this. 
[Serializable] 
public class ParserException : Exception 
{ 
 

// Constructor without arguments allows throwing your exception without 
// providing any information, including error message. Should be included 
// if your exception is meaningful without any additional details. Should 
// set message by calling base constructor (default message is not helpful). 
public ParserException() 
: base("Parser failure.") 
{} 
// Constructor with message argument allows overriding default error message. 
// Should be included if users can provide more helpful messages than 
// generic automatically generated messages. 
public ParserException(string message) 
: base(message) 
{} 
// Constructor for serialization support. If your exception contains custom 
// properties, read their values here. 
protected ParserException(SerializationInfo info, StreamingContext context) 
: base(info, context) 
{} 
} 
Using the ParserException 
try 
{ 
Process.StartRun(fileName) 
} 
catch (ParserException ex) 
{ 
Console.WriteLine($"{ex.Message} in ${ex.FileName}:${ex.LineNumber}"); 
} 
catch (PostProcessException x) 
{ 
... 
} 
You may also use custom exceptions for catching and wrapping exceptions. This way many different errors can be 
converted into a single error type that is more useful to the application: 
try 
{ 
int foo = int.Parse(token); 
} 
catch (FormatException ex) 
{ 
//Assuming you added this constructor 
throw new ParserException( 
$"Failed to read {token} as number.", 
FileName, 
LineNumber, 
ex); 
} 
When handling exceptions by raising your own custom exceptions, you should generally include a reference the 
original exception in the InnerException property, as shown above. 
Security Concerns 
If exposing the reason for the exception might compromise security by allowing users to see the inner workings of 
your application it can be a bad idea to wrap the inner exception. This might apply if you are creating a class library 
 

that will be used by others. 
Here is how you could raise a custom exception without wrapping the inner exception: 
try 
{ 
// ... 
} 
catch (SomeStandardException ex) 
{ 
// ... 
throw new MyCustomException(someMessage); 
} 
Conclusion 
When raising a custom exception (either with wrapping or with an unwrapped new exception), you should raise an 
exception that is meaningful to the caller. For instance, a user of a class library may not know much about how that 
library does its internal work. The exceptions that are thrown by the dependencies of the class library are not 
meaningful. Rather, the user wants an exception that is relevant to how the class library is using those 
dependencies in an erroneous way. 
try 
{ 
// ... 
} 
catch (IOException ex) 
{ 
// ... 
throw new StorageServiceException(@"The Storage Service encountered a problem saving 
your data. Please consult the inner exception for technical details. 
If you are not able to resolve the problem, please call 555-555-1234 for technical 
assistance.", ex); 
} 

0 Comment's

Comment Form

Submit Comment