Почему typeof (T)! = Instance.getType ()? - PullRequest
4 голосов
/ 08 апреля 2020

Я работаю на фабрике, которая должна возвращать обобщенную c реализацию интерфейса в соответствии с типом.

Мой основной вопрос иллюстрируется
enter image description here Почему эти typeof (TException)! = Exception.GetType ()? Соответственно, что я должен изменить, чтобы иметь правильный тип для TException?

Приведенный выше код приводит к исключению InvalidCast, потому что он пытается привести к IDocumedisExceptionHandler<DocumedisException> вместо IDocumedisExceptionHandler<FhirParsingException>

Реализация фабрики:

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;
    }
}

Дополнительный вопрос: есть ли лучший способ, чем использовать object в качестве значения словаря?

Регистрация обработчика при запуске:

var exceptionHandlerFactory = app.ApplicationServices.GetService<IDocumedisExceptionHandlerFactory>();
exceptionHandlerFactory.RegisterExceptionHandler(new FhirParsingExceptionHandler());

Где FhirParsingExceptionHandler реализует 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;
    }
}

Определение обработчика (где TException является контравариантным):

public interface IDocumedisExceptionHandler<in TException>
    where TException : DocumedisException
{
    void HandleException(TException exception, out HttpStatusCode httpStatusCode, out OperationOutcome.IssueType issueType, out string message);
}

И FhirParsingException расширяется DocumedisException:

public class FhirParsingException : DocumedisException
{
   [...]
}

Извлечение обработчика из промежуточного программного обеспечения:

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);
   [...]
}

1 Ответ

5 голосов
/ 08 апреля 2020

typeof(TException) дает вам время компиляции типа exception. exception.GetType() дает вам время выполнения типа exception. Эти два не обязательно должны быть одинаковыми, единственная гарантия, которую дает компилятор, заключается в том, что тип времени выполнения exception будет назначаться переменной TException.

Примите во внимание следующее:

class Animal { }
class Turtle: Animal { }
bool CheckTypes<T>(T animal) where T: Animal 
{
     return typeof(T) == animal.GetType();
}

А теперь у вас есть:

Animal animal = new Turtle();
Feed(animal);

Будьте уверены, CheckTypes вернет false; тип аргумента универсального c типа Animal, но тип времени выполнения animal действительно Turtle.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...