Reputation: 2029
I'm working on a factory which shall return a generic implementation of an interface according to a type.
My main question is being illustrated by
Why are these typeof(TException) != exception.GetType()? Respectively, what do I have to change to have the correct type for TException?
The above code results in a InvalidCast exception because it tries to cast to IDocumedisExceptionHandler<DocumedisException>
instead of IDocumedisExceptionHandler<FhirParsingException>
Factory implementation:
internal class DocumedisExceptionHandlerFactory : IDocumedisExceptionHandlerFactory
{
private readonly IDictionary<Type, object> _exceptionHandlers = new ConcurrentDictionary<Type, object>();
public void RegisterExceptionHandler<TException>(IDocumedisExceptionHandler<TException> exceptionHandler)
where TException : DocumedisException
{
_exceptionHandlers.Add(typeof(TException), exceptionHandler);
}
public IDocumedisExceptionHandler<TException> GetDocumedisExceptionHandler<TException>(TException exception)
where TException : DocumedisException
{
_exceptionHandlers.TryGetValue(exception.GetType(), out var exceptionHandler);
return (IDocumedisExceptionHandler<TException>) exceptionHandler;
}
}
Side question: Would there be a better way then using object
as dictionary value?
Registration of the handler in startup:
var exceptionHandlerFactory = app.ApplicationServices.GetService<IDocumedisExceptionHandlerFactory>();
exceptionHandlerFactory.RegisterExceptionHandler(new FhirParsingExceptionHandler());
Where FhirParsingExceptionHandler
implements IDocumedisExceptionHandler
internal class FhirParsingExceptionHandler : IDocumedisExceptionHandler<FhirParsingException>
{
public void HandleException(FhirParsingException exception, out HttpStatusCode httpStatusCode, out OperationOutcome.IssueType issueType, out string message)
{
httpStatusCode = HttpStatusCode.BadRequest;
issueType = OperationOutcome.IssueType.Invalid;
message = exception.Message;
}
}
Handler definition (where TException
is contravariant):
public interface IDocumedisExceptionHandler<in TException>
where TException : DocumedisException
{
void HandleException(TException exception, out HttpStatusCode httpStatusCode, out OperationOutcome.IssueType issueType, out string message);
}
And FhirParsingException
extends DocumedisException
:
public class FhirParsingException : DocumedisException
{
[...]
}
Retrieval of the handler from the middleware:
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
}
catch (Exception ex)
{
if (ex is DocumedisException documedisException)
{
await HandleDocumedisExceptionAsync(context, documedisException);
}
else
{
throw;
}
}
}
private async Task HandleDocumedisExceptionAsync<TException>(HttpContext context, TException ex, MedicationAnalyzerErrorCode? errorCode = null)
where TException : DocumedisException
{
var exceptionHandler = _documedisExceptionHandlerFactory.GetDocumedisExceptionHandler(ex);
[...]
}
Upvotes: 4
Views: 89
Reputation: 32750
typeof(TException)
gives you the compile time type of exception
. exception.GetType()
gives you the runtime type of exception
. These two need not be the same at all, the only guarantee the compiler makes is that the runtime type of exception
will be assignable to a TException
variable.
Consider the following:
class Animal { }
class Turtle: Animal { }
bool CheckTypes<T>(T animal) where T: Animal
{
return typeof(T) == animal.GetType();
}
And now you have:
Animal animal = new Turtle();
Feed(animal);
Rest assured, CheckTypes
will return false
; the type of the generic type argument is Animal
but the runtime type of animal
is really Turtle
.
Upvotes: 5