[英]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);
}
结合使用async
和ref
的问题在于,即使方法返回后, 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.