public static class MyContextExtensions{ public static async Task SomeFunction(this DbContext myContext){ bool output = false; //...doing stuff with myContext return output; } public static async Task<List> SomeOtherFunction(this DbContext myContext){ List output = new List(); //...doing stuff with myContext return output; } }
我的目标是能够从另一个类中的单个方法调用任何这些方法,并将其结果作为对象返回。 它看起来像这样:
public class MyHub: Hub{ public async Task InvokeContextExtension(string methodName){ using(var context = new DbContext()){ //This fails because of invalid cast return await (Task)typeof(MyContextExtensions).GetMethod(methodName).Invoke(null, context); } } }
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; }
这是一个完整的运行示例,它将上述通过reflection调用Task技术置于上下文中:
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
public static async Task Cast([NotNull] this Task task, Type type = null) { return (TResult)(object) await task.ConfigureAwait(false); } // Dummy type class public class Type { } public static class TypeExtension { public static Type ToGeneric(this T source) { return new Type(); } }
public static class TaskExtension { public async static Task Cast(this Task task) { if (!task.GetType().IsGenericType) throw new InvalidOperationException(); await task.ConfigureAwait(false); // Harvest the result. Ugly but works return (T)((dynamic)task).Result; } }
用法:
Task task = ... Task = task.Cast();
这样,您可以将Task中的Task更改为您想要的任何内容。
最有效的方法是定制awaiter:
struct TaskCast where TSource : TDestination { readonly Task task; public TaskCast(Task task) { this.task = task; } public Awaiter GetAwaiter() => new Awaiter(task); public struct Awaiter : System.Runtime.CompilerServices.INotifyCompletion { System.Runtime.CompilerServices.TaskAwaiter awaiter; public Awaiter(Task task) { awaiter = task.GetAwaiter(); } public bool IsCompleted => awaiter.IsCompleted; public TDestination GetResult() => awaiter.GetResult(); public void OnCompleted(Action continuation) => awaiter.OnCompleted(continuation); } }