簡體   English   中英

如何將帶有ref參數的函數轉換為異步函數?

[英]How can I convert a function with a ref paramter to an async function?

我有以下功能,希望將其轉換為異步/非鎖定功能。

這是當前形式的函數:

   private static void BlockForResponse(ref bool localFlag)
    {
        int count = 0;
        while (!localFlag)
        {
            Thread.Sleep(200);
            if (count++ > 50)   // 200 * 50 = 10 seconds
            {
                //timeout
                throw new TimeOutException();
            }
        }
    }

這是我的嘗試:

  private static async Task BlockForResponse(ref bool localFlag)
    {
        int count = 0;
        while (!localFlag)
        {
            await Task.Delay(200);
            if (count++ > 50)   // 200 * 50 = 10 seconds
            {
                //timeout
                throw new TimeOutException();
            }
        }
    }

但是我收到一個編譯錯誤,說異步函數不能具有ref或out參數。 但是,這是該功能的核心功能。

是否可以將其轉換為異步功能?

代碼說明:

我必須承認這是一段奇怪的代碼,讓我嘗試解釋一下它的作用:

因此,有一個我需要使用的第三方dll。 它為我提供了服務,但可惜我無法控制該dll。

它的工作方式是,我在dll中調用一個命令,為它提供一個回調函數,一旦完成任務,它將調用該函數。

一旦獲得該呼叫的結果,我就只能繼續執行我想做的事情。 因此需要該功能。

我對dll進行了調用,並為其提供了回調函數:

    private bool _commandFlag = false;
    private bool _commandResponse;

    public async Task ExecuteCommand(string userId, string deviceId)
    {
        var link = await LinkProviderAsync.GetDeviceLinkAsync(deviceId, userId);
        try
        {               
            //execute command
            if (link.Command(Commands.ConnectToDevice, CallBackFunction))
            {
                BlockForResponse(ref _commandFlag);
                return;     //Received a response
            }
            else
            {   //Timeout Error                    
                throw new ConnectionErrorException();
            }
        }
        catch (Exception e)
        {
            throw e;
        }
    }

    private void CallBackFunction(bool result)
    {
        _commandResponse = result;
        _commandFlag = true;
    }

它的工作方式是,我在dll中調用一個命令,為它提供一個回調函數,一旦完成任務,它將調用該函數。

然后,您真正想要的是使用TaskCompletionSource<T>創建TAP方法, 類似於this

public static Task<bool> CommandAsync(this Link link, Commands command)
{
  var tcs = new TaskCompletionSource<bool>();
  if (!link.Command(command, result => tcs.TrySetResult(result)))
      tcs.TrySetException(new ConnectionErrorException());
  return tcs.Task;
}

使用此擴展方法,您的調用代碼將更加整潔:

public async Task ExecuteCommand(string userId, string deviceId)
{
  var link = await LinkProviderAsync.GetDeviceLinkAsync(deviceId, userId);
  var commandResponse = await link.CommandAsync(Commands.ConnectToDevice);
}

結合使用asyncref的問題在於,即使方法返回后, async函數中的代碼也可以運行。 因此,如果您執行以下操作:

async Task BlockForResponseAsync(ref bool localFlag)
{
    while (!localFlag)
    {
        ...
    }
}

void SomeMethod()
{
    bool flag = false;
    BlockForResponseAsync(ref flag); // note: no await here
}

然后,在SomeMethod()返回之后,本地變量flag將停止存在,但是具有對該變量的引用的BlockForResponseAsync()可能仍在執行。 這就是為什么上面的代碼無法編譯的原因。

基本上,您需要一個閉包 ,在C#中, ref不會創建閉包,但是lambdas會創建閉包。 這意味着您可以這樣編寫方法:

async Task BlockForResponseAsync(Func<bool> localFlagFunc)
{
    while (!localFlagFunc())
    {
        ...
    }
}

並像這樣使用它:

bool flag = false;
var task = BlockForResponseAsync(() => flag);

// other code here

flag = true;
await task; // to make sure BlockForResponseAsync() completed successfully

這樣也可以更好地表明您的意圖。 ref通常的含義是:“給我一個具有某些值的變量,然后我將更改該值”,這不是您想要的。 另一方面, Func<T>意思是“給我一些我可以使用的東西,可能會多次獲取一些值”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM