将任何给定的函数转换为等待的任务

时间:2015-08-17 08:27:38

标签: c# async-await task-parallel-library

以下代码的目标是将任何给定的函数强制转换为等待函数。我们的想法是在从数据库中获取数据时使用它,使代码可以灵活地使用同步获取函数(强制使用当前的ORM),或者使用与async完全相同的函数。

我知道代码背后的概念可能有很多问题。到目前为止,我只是想摆脱编译器错误,所以我可以运行代码并检查行为。但我当然愿意事先讨论这个概念,如果背后的整个想法是错误的,那么就更有效地利用我的时间寻找另一种解决方案。

async static void Main()
{
    // The following line gives a compiler error:
    // Error    1   The best overloaded method match for 'CastFuncToTask<int>(System.Func<int>)' has some invalid arguments 
    int task = await CastFuncToTask<int>(TestFunc(2));
}

private static Task<T> CastFuncToTask<T>(Func<T> func)
{
    TaskCompletionSource<T> taskCompletionSource = new TaskCompletionSource<T>();
    T result = func.Invoke();
    taskCompletionSource.SetResult(result);
    return taskCompletionSource.Task;
}

private static int TestFunc(int testInt) 
{
    return testInt * 2;
}

6 个答案:

答案 0 :(得分:11)

运行.NET 4.5,您可以通过以下方式大大简化代码:

int task = await Task.FromResult(TestFunc(2));

无需将自己包裹在TaskCompletionSource

  

我知道这个概念可能有很多问题   代码背后。

如果您尝试做的是异步查询数据库,此解决方案肯定无济于事。它只会人为地将您的结果包装在Task中。如果您确实想要异步查询数据库,则需要使用数据库提供程序提供的异步方法。

如果您正在使用MySQL并寻找支持异步的驱动程序,请查看Dapper

答案 1 :(得分:3)

将其更改为

int task = await CastFuncToTask<int>(()=>TestFunc(2));

在您的代码中,为CastFuncToTask提供的输入为intTestFunc返回的内容。)但需要委托Func<T>

答案 2 :(得分:2)

我的方法是:

public Task<int> SetOffAsync()
{
    return Task<int>.Factory.StartNew(() =>
    { 
        /*do something else*/
        return 42;
    });
}

你可以这样称呼:

int var = await SetOffAsync();

答案 3 :(得分:1)

使用Windows窗体应用程序,我确认第一个调用是阻止第二个isn&t。因此,最好的解决方案是将Task.Run()与lambda表达式一起使用。

    private async void button1_Click(object sender, EventArgs e)
    {
        button1.Text = "...";
        var result = await Task.FromResult(TestFunc(2));
        button1.Text = result.ToString();
    }

    private async void button2_Click(object sender, EventArgs e)
    {
        button2.Text = "...";
        var result = await Task.Run(() => TestFunc(2));
        button2.Text = result.ToString();
    }

    private int TestFunc(int x)
    {
        System.Threading.Thread.Sleep(5000);
        return x;
    }

编译器无法知道您不想评估TestFunc(2),而是将其用作委托,并且只是首先执行该方法,而Task.FromResult将只包含return value任务。这不是你想要的。

答案 4 :(得分:0)

等待Task.Run(()=> obj.functionname());

答案 5 :(得分:0)

下面的代码可能会帮助其他人:

注意:GenericMethod是参数名称,我们将其作为泛型类型的输入(T1)和输出(T2)作为Func传递。 Task Factory将提供必要的访问权限以运行您的任务。

    public async Task<T2> GenericAsyncCall<T1, T2>(Func<T1, T2> GenericMethod, T1 input)
    {
        var _output = await Task.Factory.StartNew(() => {
            var output = GenericMethod.Invoke(input);
            return output;
        });

        return (T2)_output;
    }