投放任务< T>到Task< object>在没有T的C#中 [英] Cast Task<T> to Task<object> in C# without having T

查看:99
本文介绍了投放任务< T>到Task< object>在没有T的C#中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个充满扩展方法的静态类,其中的每个方法都是异步的,并返回一些值-像这样:

I have static class full of extension methods where each of the methods is asynchronous and returns some value - like this:

public static class MyContextExtensions{
  public static async Task<bool> SomeFunction(this DbContext myContext){
    bool output = false;
    //...doing stuff with myContext
    return output;
  }

  public static async Task<List<string>> SomeOtherFunction(this DbContext myContext){
    List<string> output = new List<string>();
    //...doing stuff with myContext
    return output;
  }
}

我的目标是能够从另一个类的单个方法中调用任何这些方法,并将其结果作为对象返回.看起来像这样:

My goal is to be able to invoke any of these methods from a single method in another class and return their result as an object. It would look something like this:

public class MyHub: Hub{
  public async Task<object> InvokeContextExtension(string methodName){
    using(var context = new DbContext()){
      //This fails because of invalid cast
      return await (Task<object>)typeof(MyContextExtensions).GetMethod(methodName).Invoke(null, context);
    }
  }
}

问题是强制转换失败.我的困境是我无法将任何类型参数传递给"InvokeContextExtension"方法,因为它是SignalR集线器的一部分,并由javascript调用.在某种程度上,我不在乎扩展方法的返回类型,因为它只会序列化为JSON并发送回javascript客户端.但是我必须将Invoke返回的值强制转换为Task才能使用await运算符.而且我必须为该任务"提供一个通用参数,否则它将把返回类型视为无效.因此,一切都取决于我如何将具有通用参数T的Task成功地转换为具有对象通用参数的Task,其中T表示扩展方法的输出.

The problem is that the cast fails. My dilemma is that I cannot pass any type parameters to the "InvokeContextExtension" method because it is part of a SignalR hub and is invoked by javascript. And to a certain extent I don't care about the return type of the extension method because it is just going to get serialized to JSON and sent back to the javascript client. However I do have to cast the value returned by Invoke as a Task in order to use the await operator. And I have to supply a generic parameter with that "Task" otherwise it will treat the return type as void. So it all comes down to how do I successfully cast Task with generic parameter T to a Task with a generic parameter of object where T represents the output of the extension method.

推荐答案

您可以分两步完成-使用基类await进行任务,然后使用反射或dynamic收获结果:

You can do it in two steps - await the task using the base class, then harvest the result using reflection or dynamic:

using(var context = new DbContext()) {
    // Get the task
    Task task = (Task)typeof(MyContextExtensions).GetMethod(methodName).Invoke(null, context);
    // Make sure it runs to completion
    await task.ConfigureAwait(false);
    // Harvest the result
    return (object)((dynamic)task).Result;
}

这是一个完整的运行示例,将通过反射调用Task的上述技术置于上下文中:

Here is a complete running example that puts in context the above technique of calling Task through reflection:

class MainClass {
    public static void Main(string[] args) {
        var t1 = Task.Run(async () => Console.WriteLine(await Bar("Foo1")));
        var t2 = Task.Run(async () => Console.WriteLine(await Bar("Foo2")));
        Task.WaitAll(t1, t2);
    }
    public static async Task<object> Bar(string name) {
        Task t = (Task)typeof(MainClass).GetMethod(name).Invoke(null, new object[] { "bar" });
        await t.ConfigureAwait(false);
        return (object)((dynamic)t).Result;
    }
    public static Task<string> Foo1(string s) {
        return Task.FromResult("hello");
    }
    public static Task<bool> Foo2(string s) {
        return Task.FromResult(true);
    }
}

这篇关于投放任务&lt; T&gt;到Task&lt; object&gt;在没有T的C#中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆