gpt4 book ai didi

c# - 在单个扩展方法中正确开始和结束调用

转载 作者:行者123 更新时间:2023-11-30 16:29:52 24 4
gpt4 key购买 nike

我想和其他人一起仔细检查这是否是创建一个扩展方法的正确方法,该扩展方法开始一个异步进程,并返回一个函数,该函数在调用时实质上等待该进程并获取结果。

    public static Func<R> HandleInvoke<T, R>(this Func<T, R> function, T arg, Action<IAsyncResult> callback)
{
IAsyncResult result = function.BeginInvoke(arg, new AsyncCallback(callback), function);

return delegate
{
return function.EndInvoke(result);
};
}

本质上我想像这样使用它(伪代码):

Func<R> myFunc = (some delegate).HandleInvoke(arg, callback);  
// at this point the operation begins, but will be nonblocking

// do other stuff

var result = myFunc(); // now I am deciding to wait on the result, which is blocking

不确定我是否需要担心在这种情况下等待 WaitHandles。也不确定是否有必要传入回调。另外我认为这构成了关闭?

编辑

结束了,

    public static Func<R> HandleInvoke<T, R>(this Func<T, R> function, T arg)
{
IAsyncResult asyncResult = function.BeginInvoke(arg, iAsyncResult =>
{
if (!(iAsyncResult as AsyncResult).EndInvokeCalled)
{
(iAsyncResult.AsyncState as Func<T, R>).EndInvoke(iAsyncResult);
}

}, function);

return delegate
{
WaitHandle.WaitAll(new WaitHandle[] { asyncResult.AsyncWaitHandle });

return function.EndInvoke(asyncResult);
};
}

这似乎运作良好。回调检查是否已调用 EndInvoke,如果没有,则调用它。否则在返回的委托(delegate)中调用 EndInvoke。

第二次编辑

这是我最近的尝试 -- 还没有向我抛出任何错误,而且似乎处理得很好。我无法让它在委托(delegate)返回 function.EndInvoke() 结果的地方工作,但委托(delegate)会等到在匿名回调中调用 EndInvoke 后再返回 R。不过,Thread.Sleep() 可能不是最佳解决方案。还可以使用更多检查来确保在每种情况下实际分配给了 R。

    public static Func<R> HandleInvoke<T, R>(this Func<T, R> function, T arg)
{
R r = default(R);

IAsyncResult asyncResult = function.BeginInvoke(arg, result =>
{
r = (result.AsyncState as Func<T, R>).EndInvoke(result);

}, function);


return delegate
{
while (!(asyncResult as AsyncResult).EndInvokeCalled)
{
Thread.Sleep(1);
}

return r;
};
}

最佳答案

这应该可行,但我不喜欢设计...这是基本问题。

如果调用了 myFunc,则不应在回调中调用 EndInvoke,但如果未调用 myFunc,因为您不关心返回值,则必须在回调中调用 EndInvoke。这使得使用 API 变得不明显且容易出错。

随着你在那里的 sleep ,它很活泼,虽然它不太可能经常咬你。这使用适当的同步原语来保证一切都以正确的顺序发生。这是未经测试的代码,但应该可以工作

    public static Func<R> HandleInvoke<T, R>(this Func<T, R> function, T arg)
{
R retv = default(R);
bool completed = false;

object sync = new object();

IAsyncResult asyncResult = function.BeginInvoke(arg,
iAsyncResult =>
{
lock(sync)
{
completed = true;
retv = function.EndInvoke(iAsyncResult);
Monitor.Pulse(sync); // wake a waiting thread is there is one
}
}
, null);

return delegate
{

lock (sync)
{
if (!completed) // if not called before the callback completed
{
Monitor.Wait(sync); // wait for it to pulse the sync object
}
return retv;
}
};
}

关于c# - 在单个扩展方法中正确开始和结束调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6093879/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com