在我的项目中,我从动态链接库引用类型和接口。
使用此特定库时,我要做的第一件事是创建EA.Repository
的实例,该实例在该库中定义,并用作进一步使用的入口点。
实例化EA.Repository repository = new EA.Repository()
在后台执行一些复杂的操作,我发现自己遇到了三种可能的结果:
我能够使用Task
提出异步方法:
public static void Connect()
{
// Do the lengthy instantiation asynchronously
Task<EA.Repository> task = Task.Run(() => { return new EA.Repository(); });
bool isCompletedInTime;
try
{
// Timeout after 5.0 seconds
isCompletedInTime = task.Wait(5000);
}
catch (Exception)
{
// If the instantiation fails (in time), throw a custom exception
throw new ConnectionException();
}
if (isCompletedInTime)
{
// If the instantiation finishes in time, store the object for later
EapManager.Repository = task.Result;
}
else
{
// If the instantiation did not finish in time, throw a custom exception
throw new TimeoutException();
}
}
(我知道,您可能已经在这里发现了很多问题。请耐心等待,建议将不胜感激!)
到目前为止,这种方法仍然有效-我可以模拟“异常”和“超时”场景,并获得所需的行为。
但是,我发现了另一种极端情况:假设实例化任务花费的时间足够长,以至于超时到期然后引发异常。在这种情况下,有时我会以AggregateException
结尾,说尚未遵守任务。
我正在努力寻找可行的解决方案。超时到期后,我无法真正取消任务,因为阻塞实例化显然使我无法使用CancellationToken
方法。
我唯一能想到的就是在抛出我的自定义TimeoutException
之前立即开始异步观察任务(即开始另一个任务):
Task observerTask = Task.Run(() => {
try { task.Wait(); }
catch (Exception) { }
});
throw new TimeoutException();
当然,如果实例化确实永远阻塞了,那么我已经完成了第一个任务,即永远无法完成。有了观察者任务,现在我什至有两个!
我对整个方法不太安全,因此欢迎提出任何建议!
非常感谢您!
答案 0 :(得分:2)
我不确定我是否完全理解您要实现的目标,但是如果您做这样的事情-
public static void Connect()
{
Task<EA.Repository> _realWork = Task.Run(() => { return new EA.Repository(); });
Task _timeoutTask = Task.Delay(5000);
Task.WaitAny(new Task[]{_realWork, timeoutTask});
if (_timeoutTask.Completed)
{
// timed out
}
else
{
// all good, access _realWork.Result
}
}
或者您甚至可以缩短一点-
public static void Connect()
{
Task<EA.Repository> _realWork = Task.Run(() => { return new EA.Repository(); });
var completedTaskIndex = Task.WaitAny(new Task[]{_realWork}, 5000);
if (completedTaskIndex == -1)
{
// timed out
}
else
{
// all good, access _realWork.Result
}
}
您也可以始终call Task.Run
with a CancellationToken
超时,但这会引发异常-上述解决方案使您可以控制行为,而不会引发异常(即使您始终可以try/catch
)
答案 1 :(得分:0)
这里是扩展方法,可用于显式观察未被观察时可能失败的任务:
public static Task<T> AsObserved<T>(this Task<T> task)
{
task.ContinueWith(t => t.Exception);
return task;
}
用法示例:
var task = Task.Run(() => new EA.Repository()).AsObserved();