在C#中使用MakeGenericMethod后,如何制作具体类型?

时间:2018-11-21 11:13:08

标签: c# rest generics casting task

有一些背景知识,我正在使用别人编写的一些代码。这是一个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,并且在调试过程中将鼠标悬停在此方法上时,都可以看到 valid 结果,但没有{{1} }成员,供我进行最终的投射。

我尝试过的事情:

我尝试使用task.Result将此handleMethod.Invoke转换为所需的'resopnseType',但由于未实现IConvertible而出现异常。我真的必须为我需要返回的每种类型实现IConvertible吗?

我也尝试将返回类型设置为Task,但是随后我需要在ResolveQuery中指定TResponse,这会导致内部服务器错误(我不确定如何从调用代码中指定TResponse)。 / p>

我也尝试过问程序员他在这里做什么。他不知道。他正在遵循另一位程序员对此实施的原始建议,但是该程序员目前不在这里,否则我会问他!

谁能告诉我如何正确地从任务对象中获取结果,并以RESTful方式将其返回给调用方客户端?

更新-回应@Yeldar Kurmangaliyev

Convert.ChangeType(result, responseType);

2 个答案:

答案 0 :(得分:1)

没有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

答案 1 :(得分:1)

几周前我也遇到了同样的问题。不幸的是,我找不到我读过那句神圣句子的页面,但它在这里:

“只有通过强制转换为dynamic才能通过反射等待通用方法,该方法可以在Task <目标类型>中进行解析”

因此,请举一个示例,说明您的情况:

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

是的,动态并不是最好的选择,但是在编译器不知道通用T参数为哪种类型的情况下会有所帮助。