using System;
namespace pc.ExceptionBubblingWithReflection {
class Person {
private string _name;
public string Name
{
get { return _name; }
set {
if (String.IsNullOrEmpty(value))
throw new ArgumentNullException(nameof(Name));
_name = value;
}
}
}
class Program {
static Person person = new Person();
static void Main(string[] args) {
Console.WriteLine("Enter in a Name");
try {
person.Name = Console.ReadLine();
}
catch (ArgumentNullException anEx) {
Console.WriteLine(anEx.Message);
}
//pause here
Console.ReadKey();
}
}
}
now what do i mean by silent? I mean the debugger wont break the execution of your code when the exception is thrown in the setter of the Name property, you're probably thinking "No shit Sherlock"; well try the same principle but use reflection to set the Name property instead.
using System;
namespace pc.ExceptionBubblingWithReflection {
class Person {
private string _name;
public string Name
{
get { return _name; }
set {
if (String.IsNullOrEmpty(value))
throw new ArgumentNullException(nameof(Name));
_name = value;
}
}
}
class Program {
static Person person = new Person();
static void Main(string[] args)
{
Console.WriteLine("Enter in a Name");
try {
var pi = typeof(Person).GetProperty("Name");
pi.SetValue(person, Console.ReadLine());
}
catch (ArgumentNullException ex) {
Console.WriteLine(ex.Message);
}
//pause here
Console.ReadKey();
}
}
}
Immediately you notice a TargetInvocationException, so let's deal with tat first. let's inspect the TargetInvocationException; when inspecting it we should notice that it's inner exception contains our ArgumentNullException, so let's modify our code to expose the message of our original exception.
class Program {
static Person person = new Person();
static void Main(string[] args)
{
Console.WriteLine("Enter in a Name");
try {
var pi = typeof(Person).GetProperty("Name");
pi.SetValue(person, Console.ReadLine());
}
catch (TargetInvocationException tiEx) {
Console.WriteLine(tiEx.InnerException.Message);
}
//pause here
Console.ReadKey();
}
}
Now by catching the TargetInvocatioException we are back on easy street, except for one bizarre behavior; our debugger still highlights our ArgumentNullException when we throw it.
if we continue our application executes as expected, however this can prove to be a pain when demoing an application or even when debugging. In comes the [DebuggerStepThrough] attribute to save the day, just add it to the setter of the Name attribute.
using System;
using System.Diagnostics;
using System.Reflection;
namespace pc.ExceptionBubblingWithReflection {
class Person {
private string _name;
public string Name
{
get { return _name; }
[DebuggerStepThrough]
set {
if (String.IsNullOrEmpty(value))
throw new ArgumentNullException(nameof(Name));
_name = value;
}
}
}
class Program {
static Person person = new Person();
static void Main(string[] args)
{
Console.WriteLine("Enter in a Name");
try {
var pi = typeof(Person).GetProperty("Name");
pi.SetValue(person, Console.ReadLine());
}
catch (TargetInvocationException tiEx) {
Console.WriteLine(tiEx.InnerException.Message);
}
//pause here
Console.ReadKey();
}
}
}
One caveat to be aware of is that by adding the [DebuggerStepThrough] attribute all exceptions will be stepped over in the setter by the debugger regardless if they are handled or not.