Generic method called base type
I have a situation like this:
public class Foo{}
public interface IBar<in TEx>
where TEx : Exception
{
Foo Build(TEx ex);
}
public class FooFactory{
public Foo Create<TEx>(TEx ex) where TEx : Exception{
// blah
}
}
If I call a method FooFactory.Create
passing any type of exception everything works. Things start to get weird when I do something like this:
// this is an external class, cannot be changed.
public class ExceptionContext{
public Exception Ex{get; set;}
}
var context = new ExceptionContext(){ Ex = new MyCustomException (); }
var factory = new FooFactory();
var fooInstance = factory.Create(context.Ex);
When I call FooFactory.Create()
, the past exception is always of type System.Exception
, not MyCustomException
as I would expect.
Any suggestion?
EDIT: Just to give a little context, I'm trying to run exception-specific code in an OnException context (ExceptionContext method) for a custom Microsoft.AspNetCore.Mvc.Filters.IExceptionFilter implementation.
source to share
When I call
FooFactory.Create()
, the past exception is always of typeSystem.Exception
This is because the static type ExceptionContext.Ex
is Exception
. The generic method is bound at compile time, which does not know the dynamic runtime type is different.
The next best option is to specify the run-time type at compile time using an explicit cast:
var fooInstance = factory.Create((MyCustomException)context.Ex);
Which obviously assumes that the type is runtime MyCustomException
. If it is not, you will get an invalid cast exception.
You can also use dynamic
to defer method resolution until runtime:
dynamic fooInstance = factory.Create((dynamic)context.Ex);
The risk here is that whatever is using fooInstance
will be dynamic as well, so you won't get any security at compile time, and any errors (misspelled names, wrong parameter types) won't be caught until runtime.
EDIT
Removed this part of the answer as ExceptionContext
it is not under the control of the OPs.
You can do ExceptionContext
general:
public class ExceptionContext<TEx>
where TEx : Exception
{
public <TEx> Ex{get; set;}
}
var context = new ExceptionContext<MyCustomException>(){ Ex = new MyCustomException (); }
var factory = new FooFactory();
var fooInstance = factory.Create(context.Ex);
Or add a constructor if you want to use the parameter output:
public class ExceptionContext<TEx>
where TEx : Exception
{
public ExceptionContext(TEx exception)
{
this.Ex = exception;
{
public <TEx> Ex{get; set;}
}
var context = new ExceptionContext(new MyCustomException());
var factory = new FooFactory();
var fooInstance = factory.Create(context.Ex);
But it is not clear if this is the case for your program as a whole. Strike>
source to share
Consider creating a generic class as well ExceptionContext
:
public class ExceptionContext<TEx> where TEx : Exception
{
public TEx Ex{get; set;}
}
This way, the most derived type of the exception is preserved, not the most basic type (in your case System.Exception
).
The exception to this rule is, of course, when your exception is an instance System.Exception
.
source to share