C# 如果我不再关心结果,是否还有终止委托的方法?

C# 如果我不再关心结果,是否还有终止委托的方法?,c#,multithreading,delegates,C#,Multithreading,Delegates,我有一段代码可以搜索几个第三方API。我根据搜索条件将搜索分为两组。我启动两个搜索,因为每个搜索都非常及时,但是如果第一组搜索结果匹配,我不想等待第二组搜索完成。所以基本上我有: Dictionary<string, string> result = null; NameSearchDelegate nameDel = new NameSearchDelegate(SearchByName); IAsyncResult nameTag = nameDel.BeginInvoke(na

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

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;
字典结果=null;
NameSearchDelegate nameDel=新的NameSearchDelegate(SearchByName);
IAsyncResult nameTag=nameDel.BeginInvoke(name,null,null);
如果(!string.IsNullOrWhiteSpace(telNum))
{
result=SearchByTelNum(telNum);//如果找不到匹配项,将返回null
}
if(null==结果)
{
结果=nameDel.EndInvoke(nameTag);
}
//结束委托以防止内存泄漏
//否则
//{
//nameDel.EndInvoke(nameTag)
//}
返回结果;

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

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

public class AbortableParameter<T>
{
    public T Parameter { get; private set }
    public bool ShouldAbort { get; set; }
    public AbortableParameter(T parameter)
    {
        Parameter = parameter;
        ShouldAbort = false;
    }
}
公共类abortable参数
{
公共T参数{get;私有集}
公共bool应该中止{get;set;}
公共中止参数(T参数)
{
参数=参数;
ShouldAbort=false;
}
}
只需创建这个类的一个实例,其中包含要传递给委托的任何参数,并保留对它的引用;如果代理应该退出,则将其设置为true。然后,代理需要定期检查
ShouldAbort
,并在它变为
true
时优雅地退出

这是缺点,代理必须定期检查,否则它是否应该中止就无关紧要了


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

我能够使用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中发生了不好的事情,您可能会在无限循环中永远等待。通过这种方式,我可以设置一个时间量,在该方法被认为超时之前,调用线程将继续运行。在本例中,由于我每0.5秒检查一次bw.IsBusy,超时长度等于timeOutCount/2秒


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

可能重复“像经理一样思考”——不要告诉学员它的工作不再有用,让它继续下去,忽略它的结果。是的,我同意D Stanley的观点。您可以调用两个搜索,只使用第一个返回的结果。根据此条件,终止委托可能无助于节省资源。但是,如果不对委托调用EndInvoke,我是否不允许可能的内存泄漏?作为参考,它是.NET4.0,我想我在这里找到的John Koerner引用的线程中找到了我想要的答案。通过使用BackgroundWorker,(System.ComponentModel.BackgroundWorker),我可以调用CancelAsync方法来“取消”线程。我现在正在尝试,并会让你知道它是如何进行的。
while(bw.IsBusy) System.Threading.Thread.Sleep(500)