我具有带操作参数的此函数,执行该参数后,该函数上的参数将具有值。我有办法获得价值吗?
public void DetailsAsync(string param1, string param2,Action<IList<Detail>> callback)
{
//process happen here and will have a callback to produce the data for detail
}
public class DetailController:ApiController
{
private IList<Detail> details;
private DetailCompleted(IList<Detail> detail)
{
//now detail parameter has a value that I can use
details = detail;
}
[HttpGet]
public IList<Detail> GetDetails()
{
ServiceManager.DetailsAsync("param1","param2",detailsCompleted)
//after ServiceManager.DetailsAsync it will go to return details
return details;
}
}
尝试此代码时,我在返回详细信息上放置了一个断点,在detailsCompleted上放置了断点,但是发生的是,当我调用Web api GetDatails时,它将首先执行返回详细信息,然后立即执行detailsCompleted函数。这就是为什么我目前无法获得价值的原因。
答案 0 :(得分:2)
Action<T>
的返回值默认为void。如果要返回值,则应使用Func<T,TResult>
https://docs.microsoft.com/en-us/dotnet/api/system.func-2?view=netframework-4.7.2
答案 1 :(得分:2)
我认为这里的问题是,DetailsAsync()
(按名称暗示)是异步的,您在等待DetailsAsync()
的结果之前返回详细信息。
因此,您应该await
,但由于DetailsAsync
返回void
,所以您不能这样做。
因此,您可以将DetailsAsync
封装在一个Task中,然后.Wait()
包裹起来,但这有点烂,因为您将阻塞调用线程。
[HttpGet]
public IList<Detail> GetDetails()
{
Task.Run(() =>
ServiceManager.DetailsAsync("param1", "param2", detailsCompleted)
).Wait();
return details;
}
答案 2 :(得分:1)
由于DetailsAsync
的编写方式,您将需要某种信令系统来暂停GetDetails
的执行,直到触发回调为止。 options有几个,但是我选择一个AutoResetEvent
是因为它很容易使用和理解。
(我已经更改了一些返回类型,以便不必创建伪造的类来匹配您的代码)
public class DetailController
{
private IList<int> details;
private AutoResetEvent callbackSignal = new AutoResetEvent(false);
private void DetailCompleted(IList<int> detail)
{
details = detail;
callbackSignal.Set();
}
public IList<int> GetDetails()
{
ServiceManager.DetailsAsync("param1", "param2", DetailCompleted);
callbackSignal.WaitOne();
return details;
}
}
callbackSignal.WaitOne();
将一直阻塞,直到“已发送信号”为止。在回调方法中,callbackSignal.Set();
发送信号,告诉等待事件的任何人现在可以继续进行。
在不确切知道如何实现DetailsAsync
的情况下,我不能保证这会成功,但是我充满希望。如果需要,您可能还必须添加一些其他保护以确保它是完全可重入的。
如果您想使用更现代的async
/ await
模式,则可以使用DetailsAsync
返回并使用的方法包装对Task
访问的访问权,并使用TaskCompletionSource
来编排回调并返回值。
public class DetailController
{
public async Task<IList<int>> GetDetails()
{
var details = await ServiceWrapper.GetDetails();
return details;
}
}
public static class ServiceWrapper
{
public static Task<IList<int>> GetDetails()
{
var tcs = new TaskCompletionSource<IList<int>>();
ServiceManager.DetailsAsync("param1", "param2", (IList<int> details) =>
{
tcs.SetResult(details);
});
return tcs.Task;
}
}