如果我不再关心结果,无论如何都要结束委托

本文关键字:结束 无论如何 不再 关心 结果 如果 | 更新日期: 2023-09-27 17:56:48

我有一段代码可以搜索多个第三方API。 我根据搜索条件将搜索分为 2 组。 我开始两个搜索是因为每个搜索都非常及时,但如果第一组搜索结果匹配,我不想等待第二个搜索组完成。 所以基本上我所拥有的是:

Dictionary<string, string> result = null;
NameSearchDelegate nameDel = new NameSearchDelegate(SearchByName);
IAsyncResult nameTag = nameDel.BeginInvoke(name, null, null);
if(!string.IsNullOrWhiteSpace(telNum))
{
    result = SearchByTelNum(telNum);//Will return null if a match is not found
}
if(null == result)
{
    result = nameDel.EndInvoke(nameTag);
}
//End the delegate to prevent memory leak
//else
//{
//    nameDel.EndInvoke(nameTag)
//}
return result;

所以我想在调用 SearchByTelNum 之前启动 SearchByName,以防它找不到匹配项,但是如果它确实找到了匹配项,我不想在返回匹配项之前等待 SearchByName 完成。 如果我不再需要其结果,有没有办法简单地结束或取消该委托?

如果我不再关心结果,无论如何都要结束委托

我能够使用 System.ComponentModel.BackgroundWorker 解决我的问题。我不一定按照它想要的方式使用它,但它能够做我需要的事情。 所以基本上我的新代码看起来像:

Dictionary<string, string> telResult = null,
                           nameResult = null;
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += (obj, e) => nameResult = SearchByName(name, bw);
bw.RunWorkerAsync();
if(!string.IsNullOrWhiteSpace(telNum))
    telResult = SearchByTelNum(telNum);//Will return null if a match is not found
if(telResult != null)
{
    bw.CancelAsync;
    return telResult;
}
bool hasTimedOut = false;
int i = timeOutCount;
while (bw.IsBusy && !hasTimedOut)
{
    System.Threading.Thread.Sleep(500);
    if (0 == --i) hasTimedOut = true;
}
return nameResult;

为了确保没有错误,我必须确保SearchByName定期检查是否bw。CancelPending 等于 true,在这种情况下结束该方法。 CancelAsync 不会结束工作线程,它只是提醒工作线程调用方线程已取消它。

我也可以简单地使用

while(bw.IsBusy) System.Threading.Thread.Sleep(500)

等待方法完成,但如果 SearchByName 中发生了不好的事情,您最终可能会在无限循环中永远等待。 这样,我可以在方法被认为超时并且调用方线程继续生活之前设置一个时间量。在这种情况下,因为我检查了 bw。每 .5 秒忙碌一次,超时长度等于超时输出计数/2 秒。

好的,我想我已经彻底回答了我自己的问题。

我已经通过定义一个可中止的参数对象来处理这个问题

public class AbortableParameter<T>
{
    public T Parameter { get; private set }
    public bool ShouldAbort { get; set; }
    public AbortableParameter(T parameter)
    {
        Parameter = parameter;
        ShouldAbort = false;
    }
}

只需使用要传递给委托的任何参数创建此类的实例,并保留对它的引用;如果委托应退出,则将其设置为 true。 然后,委托需要定期检查ShouldAbort,并在true时正常退出。

这是缺点,委托必须定期检查,否则是否应该中止都无关紧要。

也可以让 ShouldAbort 属性的 set 方法在设置为 true 时杀死委托,但这不是一个优雅的退出,在大多数情况下应避免 - 但它确实具有不需要委托轮询的好处。