Как сделать конкретный тип после использования MakeGenericMethod в C #? - PullRequest
0 голосов
/ 21 ноября 2018

Немного предыстории, я работаю с кодом, написанным кем-то другим.Это REST API, к которому вы можете выдавать запросы и команды, и они обрабатываются в общем виде.

Метод разрешения запросов выглядит примерно так:

[HttpPost]
[Route("query")]
public async Task<Task> ResolveQuery(ApiQuery message)
{
    var type = Type.GetType(message.QueryType, true);
    var query = this.serializer.Deserialize(message.Payload, type);
    var interfaceType = type.GetGenericInterfaces(typeof(IQuery<>)).FirstOrDefault();
    var responseType = interfaceType.GetGenericArguments()[0];
    var handleMethod = typeof(IQueryBus).GetMethod("ResolveAsync").MakeGenericMethod(responseType);
    var task = handleMethod.Invoke(this.bus, new object[] { query }) as Task;
    await task;
    return task;
}

Я почти увереночень необычно использовать задачи таким образом.

Так что, когда handleMethod вызывается, даже если его результат приводится в виде Задачи, и я вижу действительный результат, когда янаведите указатель мыши на него во время отладки, и у меня нет элемента task.Result, который я мог бы использовать для возможного приведения.

То, что я пробовал:

Я пытался привести этот handleMethod.Invoke в качествеМне нужен 'resopnseType', использующий Convert.ChangeType(result, responseType);, но я получаю исключение из-за отсутствия реализации IConvertible.Действительно ли мне нужно реализовать IConvertible для каждого возвращаемого типа?

Я также попытался установить тип возвращаемого значения для Task, но затем мне нужно указать TResponse в ResolveQuery, и это приведет к внутренней ошибке сервера.(Я не уверен, как я определяю TResponse из моего кода вызова).

Я также пытался спросить программиста, что он здесь делает.Он не знает.Он следовал первоначальному совету другого программиста для этой реализации, но этого программиста сейчас нет, иначе я бы спросил его!

Может кто-нибудь сказать мне, как правильно получить мой результат из объекта задачи ивернуть его в режиме RESTful вызывающему клиенту?

Обновление - в ответ на @Yeldar Kurmangaliyev

public interface IQueryBus
{
    Task<TResponse> ResolveAsync<TResponse>(IQuery<TResponse> query);
}

Ответы [ 2 ]

0 голосов
/ 21 ноября 2018

Я столкнулся с той же самой проблемой несколько недель назад.К сожалению, я не могу найти страницу, на которой я прочитал это священное предложение, но вот оно:

"Ожидание универсальных методов с помощью отражения возможно только с приведением к dynamic, которое разрешается в Задаче <тип цели>"

Итак, чтобы дать вам пример того, как он должен выглядеть в вашем случае:

dynamic taskResult = await (dynamic)handleMethod.Invoke(this.bus, new object[] { query });

Да, динамический не самая лучшая вещь, но помогает в таких сценариях, где компилятор не имеет представления о том, какого типабудет общий параметр T.

0 голосов
/ 21 ноября 2018

Нет Result, потому что это просто неуниверсальный Task.
Чтобы получить результат, вам нужно Task<T>.Поскольку вы не знаете T во время разработки, вам нужно снова использовать отражение:

public async Task<object> ResolveQuery(ApiQuery message)
{
    var type = Type.GetType(message.QueryType, true);

    var query = this.serializer.Deserialize(message.Payload, type);
    var interfaceType = type.GetGenericInterfaces(typeof(IQuery<>)).Single();
    var responseType = interfaceType.GetGenericArguments().Single();
    var handleMethod =     typeof(IQueryBus).GetMethod("ResolveAsync").MakeGenericMethod(responseType);
    var task = (Task)handleMethod.Invoke(this.bus, new object[] { query });
    await task;

    return typeof(Task<>).MakeGenericType(responseType).GetProperty("Result").GetValue(task);
}

. Это создаст свойство Result для вашего конкретного Task<responseType> и вернет его значение.

Я также немного обновил существующий код, просто как предложение:

  • Изменены [0] и .FirstOrDefault() на .Single(), чтобы избежать NullReferenceException, потому что этоожидается, что существует ровно одно значение
  • , заменяемое as Task на прямое приведение, поскольку ожидается, что оно будет Task
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...