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.

+3


source to share


2 answers


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>

+8


source


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

.

+3


source







All Articles