C#等待lambda回调完成

问题描述 投票:0回答:2

摘要

我目前正在尝试使用MySQL数据库库执行select语句,并以回调的方式将其返回给匿名语句lambda。这就是这个特定的库(大多数是未记录的)如何处理请求。我还需要等待此过程完成。

[我目前正在尝试使用async方法,但是似乎断言任务的完成为时过早(即await taskName;在回调完成之前被绕过,因此返回的字典为空) 。

[我尝试使用完成标志方法,其中布尔标志用于表示回调是否已完成,并在返回任务之前的while循环中使用Task.Yield()

下面是来自两个不同类的两个函数。第一个来自数据库类,第二个来自实用程序类(从中调用数据库类)。

代码

/// <summary>
/// Asynchronously executes a select MySQL statement and returns a dictionary of rows selected.
/// </summary>
/// <param name="statement"></param>
/// <returns></returns>
public async Task<Dictionary<int, object>> ExecuteSelectAsync (string statement)
{
    // Init dictionary of rows and counter for each row
    Dictionary<int, object> responseData = new Dictionary<int, object>();
    int i = 0;

    bool complete = false;

    DatabaseLibrary.execute(
        statement,
        new Action<dynamic> (s =>
        {
            // Take the data returned as 's' and populate the 'responseData' dictionary.
            Utility.LogDebug("Database", "Executed select statement with " + numberOfRows.ToString() + " rows");
        })
    );

    Utility.LogDebug("Database", "Returning select execution response"); // By this point, the lambda expression hasn't been executed.
    return responseData; // This is empty at time of return.
}
/// <summary>
/// Checks the supplied data against the database to validate.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static async Task<bool> ValidateData(string data)
{
    Database database = new Database();

    Task<Dictionary<int, object>> selectTask = database.ExecuteSelectAsync("SELECT fieldname FROM tablename WHERE data='" + data + "'"); // Excuse statement forming, this is just to test
    await selectTask;

    try
    {
        Dictionary<string, object> firstRow = (Dictionary<string, object>)selectTask.Result[0];

        if ((int)firstRow["fieldname"] == 0) return false; // data not valid, return false
        else return true; // data valid, return true
    }
    catch (Exception e)
    {
        LogException("Utility", e);
        LogDebug("Utility", "Database class returned empty result set");
        return false; // Empty result, presume false
    }            
}

我知道此代码有效,在显示Returning select execution response控制台输出后不久,输出了第二行,即Executed select statement with x rows这里的主要问题是存在竞争条件。如何确保在处理数据之前正确填充了数据?

c# mysql asynchronous lambda callback
2个回答
1
投票

您将需要一种方法使数据库回调向您的代码发出已被调用的信号,并且可以恢复执行。最简单的方法是使用TaskCompletionSource。它看起来像:

TaskCompletionSource

0
投票

扩展Bradley的答案:多年来,已经有多种方式使某些东西异步化。较旧的方法是使用回调:您传递一种在工作完成时将被调用的方法。这就是您的public async Task<Dictionary<int, object>> ExecuteSelectAsync (string statement) { // declare the TaskCompletionSource that will hold the database results var tcs = new TaskCompletionSource<Dictionary<int, object>>(); DatabaseLibrary.execute( statement, new Action<dynamic> (s => { // Take the data returned as 's' and populate the 'responseData' dictionary. Utility.LogDebug("Database", "Executed select statement with " + numberOfRows.ToString() + " rows"); var data = new Dictionary<int, object>(); // build your dictionary here // the work is now complete; set the data on the TaskCompletionSource tcs.SetResult(data); }) ); // wait for the response data to be created var responseData = await tcs.Task; Utility.LogDebug("Database", "Returning select execution response"); return responseData; // if you don't need the logging, you could delete the three lines above and // just 'return tcs.Task;' (or move the logging into the callback) } 方法正在做的事情。

但是发现它使代码混乱,或有人称它为execute

因此"callback hell" / async已创建。在.NET中,它称为await(TAP),它使您可以编写看起来像同步代码的异步代码,从而更容易理解正在发生的事情。

通过使用Task-based asynchronous pattern,您正在将回调模式转换为基于任务的模式,以便可以使用TaskCompletionSource并使代码更易于理解。

© www.soinside.com 2019 - 2024. All rights reserved.