2

Consider this function:

static void Throw<T>(string message) where T : Exception
{
    throw (T)Activator.CreateInstance(typeof(T), message, (Exception)null);
}

Given a type T of System.ArgumentException, as the question title says, I get a runtime error of "Ambiguous Match Found". Looking at the documentation for ArgumentException, the following are the public constructors:

ArgumentException()
ArgumentException(string)
ArgumentException(SerializationInfo, StreamingContext)
ArgumentException(string, Exception)
ArgumentException(string, string)
ArgumentException(string, string, Exception)

Given I am passing 2 arguments in to CreateInstance, and forcing the null to be a null Exception, I am struggling to understand why it is not matching the 4th constructor in the above list?

Moo-Juice
  • 38,257
  • 10
  • 78
  • 128
  • why don't you just `throw new DerivedException(..)` instead of calling this `Throw` method. It doesn't seem to add any value apart from polluting your callstack. – Jakub Konecki Jan 30 '14 at 12:01
  • @JakubKonecki, in reality `Throw` is an extension method on `bool`. There's a lot of code that was `if(x) throw blah` `if(y & z) throw blah2`. The extension method made this somewhat cleaner and (personally) I don't find the call-stack overly polluted as we know where to look. – Moo-Juice Jan 30 '14 at 12:03

2 Answers2

5

That will work:

static void Throw<T>(String message) 
  where T: Exception { // <- It's a good style to restrict T here

  throw (T) typeof(T).GetConstructor(new Type[] {typeof(String)}).Invoke(new Object[] {message});
}

Typical Exception has 4 or more constructors, so we'd rather point out which one we want to execute. Often, we have to check if there's a suitable constructor:

static void Throw<T>(String message) 
  where T: Exception { // <- It's a good style to restrict T here

  // The best constructor we can find
  ConstructorInfo ci = typeof(T).GetConstructor(new Type[] {typeof(String)});

  if (!Object.ReferenceEquals(null, ci))
    throw (T) ci.Invoke(new Object[] {message});

  // The second best constructor
  ci = typeof(T).GetConstructor(new Type[] {typeof(String), typeof(Exception)}); 

  if (!Object.ReferenceEquals(null, ci))
    throw (T) ci.Invoke(new Object[] {message, null});
  ...
}

However, in your case you can put it with Activator:

static void Throw<T>(String message) 
  where T: Exception { // <- It's a good style to restrict T here

  throw (T) Activator.CreateInstance(typeof(T), message);
}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • For more information, the 2nd bit of code is what I *used* to have. However, my derived exceptions (for better or worse - you can be the judge), have constructors such as `(string message, Exception inner = null)`, which gives a `MissingMethod` exception (because of the default parameter), hence the `null` added to take care of that. – Moo-Juice Jan 30 '14 at 11:55
  • Also, in the actual code, it *is* constrained by the `where` clause, but have amended the original question anyway. – Moo-Juice Jan 30 '14 at 11:56
  • @JakubKonecki, I think you meant to put that comment on the other answer :) – Moo-Juice Jan 30 '14 at 11:58
  • @Moo-Juice: In this case, I think, you have to use reflection: try to find out the best constructor, then the second best one, etc. – Dmitry Bychenko Jan 30 '14 at 12:06
1

This might work

static void Throw<T>(string message)
{
    Exception ex = null;
    throw (Exception)Activator.CreateInstance(typeof(T), message, ex);
}

I don't know where Exception is on this list, but my guess is it is as specific as string, otherwise there wouldn't be a problem. How does the method overload resolution system decide which method to call when a null value is passed?

Community
  • 1
  • 1
Robert Fricke
  • 3,637
  • 21
  • 34