如何等待从异步方法(C#)接收回调

如何等待从异步方法(C#)接收回调,c#,unity3d,asynchronous,task,C#,Unity3d,Asynchronous,Task,我有一个从Firebase获取一些值的方法,如下所示: void getTable(Action<IDictionary> callBack) { // function & data initialized here function.CallAsync(data).ContinueWith((callTask) => { if (callTask.IsFaulted)

我有一个从Firebase获取一些值的方法,如下所示:

 void  getTable(Action<IDictionary> callBack)
    {
         // function & data initialized here
        function.CallAsync(data).ContinueWith((callTask) =>
        {
            if (callTask.IsFaulted)
               callBack(null);
            else if (callTask.IsCompleted)
            {    
                Debug.Log("I am being executed when done");
                var result = (IDictionary) callTask.Result.Data;
                callBack(result);
            }
        });
     }
预期产出:

  • 我被处决了
  • 完成获取值
  • 值为:testValue
  • 完成执行
  • 我得到的结果是:

  • 我被处决了
  • 值为:(空)
  • 完成执行
  • 完成获取值

  • 我试图在GetTable方法的lambda表达式中分配“valueReturned”。但它给出了错误:“不能在lambda表达式中使用ref参数”

    考虑从
    getTable
    返回
    Task
    ,并在
    getTable
    中等待它:

    Task getTable(Action<IDictionary> callBack)
    {
         // function & data initialized here
        return function.CallAsync(data).ContinueWith((callTask) =>
        {
            if (callTask.IsFaulted)
               callBack(null);
            else if (callTask.IsCompleted)
            {    
                Debug.Log("I am being executed when done");
                var result = (IDictionary) callTask.Result.Data;
                callBack(result);
            }
        });
     }
    
    public Task<string> GetTable()
    {
        string val = await getTable((dictionary =>
        {
            Debug.Log("Done getting values");
            val = (string) dictionary["someValue"]; // returns "testValue" to val
        }));
    
        Debug.Log("Value is:" + val);
        Debug.Log("Completed Execution");
        return val;
    }
    
    任务可获取(操作回调)
    {
    //函数和数据在此初始化
    return function.CallAsync(data).ContinueWith((callTask)=>
    {
    if(callTask.IsFaulted)
    回调(空);
    else if(callTask.IsCompleted)
    {    
    Log(“完成时我正在执行”);
    var result=(IDictionary)callTask.result.Data;
    回调(结果);
    }
    });
    }
    公共任务GetTable()
    {
    字符串val=wait getTable((字典=>
    {
    Log(“获取值完成”);
    val=(字符串)字典[“someValue”];//将“testValue”返回给val
    }));
    Log(“值为:”+val);
    Debug.Log(“已完成的执行”);
    返回val;
    }
    
    否则,您的
    getTable
    方法将启动一个
    任务并继续执行,因此
    getTable
    null
    赋值给
    valueReturned
    (假设
    CallAsync
    运行的时间足够长)并继续执行。我还想说,您可以从
    getTable
    返回
    Task


    如果出于某种原因,您无法使代码异步,那么根据您的上下文,有多种选择,其中一些可能比其他更合适,但无论哪种方法,您都应谨慎处理。

    编写
    getTable
    的更惯用方法是:

    async Task getTable(Action<IDictionary> callBack)
    {
        IDictionary result;
        try
        {
            result = await function.CallAsync(data);
        }
        catch
        {
            result = null;
        }
        callback(result);
    }
    
    异步任务可获取(操作回调) { 词典结果; 尝试 { 结果=wait function.CallAsync(数据); } 抓住 { 结果=空; } 回调(结果); }
    (这是否真的是一个好主意是另一个问题,因为您牺牲了错误信息,而将异步方法转换为回调通常是毫无意义的…)

    但是您的
    GetTable
    方法注定要失败。您永远不能在输出参数中返回异步调用的结果,因为在内部调用完成之前,外部函数已经退出。唯一可行的方法是
    GetTable
    GetTable
    上执行阻塞等待,这首先破坏了使用异步的整个要点


    唯一真正的答案是,您当前的设计是错误的,您需要以不同的方式进行。异步始终是唯一的方法。

    如果我们将您的私有方法剥离到核心,那么只不过是这样:

    private async Task<IDictionary> getTable()
    {
        // function & data initialized here
        var result = await function.CallAsync(data);
        return result?.Data;
    }
    
    public async Task<string> GetTable()
    {
        var dictionary = await getTable();
        var valueReturned = (string)dictionary["someValue"]; // returns "testValue" to val
        Debug.Log("Value is:" + valueReturned);
        Debug.Log("Completed Execution");
        return valueReturned;
    }
    
    正如@Miral所说:“这种设计是错误的”。从asyn/await的角度来看,我们可以将两个函数重构为一个简单的异步方法:

    public async Task<string> GetTableAsync()
    {
        // <function & data initialized here>
        var result = await function.CallAsync(data);
        var dictionary = result?.Data;
        return dictionary == null ? null: (string)dictionary["someValue"];
    }
    
    公共异步任务GetTableAsync() { // var result=await function.CallAsync(数据); var字典=结果?数据; 返回dictionary==null?null:(字符串)dictionary[“someValue”]; } 您的
    函数.CallAsync(data).ContinueWith
    不等待,这就是为什么您在“完成获取值”之前获得“已完成的执行”。正如@Miral提到的:将异步方法转换为回调是毫无意义的。
    public void GetTable(ref string valueReturned)
    {
        var dictionary = getTable().Result;
        valueReturned = (string)dictionary["someValue"]; // returns "testValue" to val
        Debug.Log("Value is:" + valueReturned);
        Debug.Log("Completed Execution");
    }
    
    public async Task<string> GetTableAsync()
    {
        // <function & data initialized here>
        var result = await function.CallAsync(data);
        var dictionary = result?.Data;
        return dictionary == null ? null: (string)dictionary["someValue"];
    }