我正在编写一个自定义报告工具,允许用户创建一些非常广泛的查询。我想为此添加一个超时,这样如果用户创建的东西最终会运行很长时间,整个系统就不会停止。我想出了这个:
public List<List<SimpleDisplayField>> FindReport(int reportId)
{
var report = GetReportById(reportId);
var tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
int timeOut = 20000; // 2 seconds
if (report.BidType == "LOB")
{
var task = Task.Factory.StartNew(() => FindLOBReport(report), token);
if (!task.Wait(timeOut, token))
{
throw new Exception("Report ran for more than 10 seconds.. run again or add more filters.");
}
return task.Result;
}
else
{
var task = Task.Factory.StartNew(() => FindFWOReport(report), token);
if (!task.Wait(timeOut, token))
{
throw new Exception("Report ran for more than 10 seconds.. run again or add more filters.");
}
return task.Result;
}
}
哪个好,但是我想把它重构成这样的东西,使用Func,所以我可以将FindLOBReport或FindFWOReport作为参数传递:
public List<List<SimpleDisplayField>> FindReport(int reportId)
{
var report = GetReportById(reportId);
if (report.BidType == "LOB")
{
return RunReport(FindLOBReport(report));
}
else
{
return RunReport(FindFWOReport(report));
}
}
private List<List<SimpleDisplayField>> RunReport(Func<CustomReport, List<List<SimpleDisplayField>>> method)
{
var tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
int timeOut = 20000; // 2 seconds
var task = Task.Factory.StartNew(() => method, token);
if (!task.Wait(timeOut, token))
{
throw new Exception("Report ran for more than 10 seconds.. run again or add more filters.");
}
return task.Result;
}
但是,task.Result是一个'Func'返回类型,而我只想让task.Result返回我的List&gt;。有什么方法可以解决这个问题吗?
答案 0 :(得分:3)
在RunReport
方法中,您实际上并没有调用method
Func。您正在重新调整method
代理人。这就是为什么Task.Result
被推断为Func<>
。
var task = Task.Factory.StartNew(() => method, token);
以上代码等于
var task = Task.Factory.StartNew(() =>
{
return method;
}, token);
要执行它,您需要使用方法调用语法来调用它。
var task = Task.Factory.StartNew(() => method(report), token);
为此,您需要将报告作为参数。
private List<List<SimpleDisplayField>> RunReport(Func<CustomReport, List<List<SimpleDisplayField>>> method,CustomReport report)
{
var tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
int timeOut = 20000; // 2 seconds
var task = Task.Factory.StartNew(() => method(report), token);
if (!task.Wait(timeOut, token))
{
throw new Exception("Report ran for more than 10 seconds.. run again or add more filters.");
}
return task.Result;
}
然后你可以把它称为
public List<List<SimpleDisplayField>> FindReport(int reportId)
{
var report = GetReportById(reportId);
return (report.BidType == "LOB")
? RunReport(FindLOBReport, report)
: RunReport(FindFWOReport, report);
}
另外值得注意的是,Task
未被取消。它将继续运行。需要注意的是一件重要的事情。如果您的FindLOBReport
方法基本上称为数据库,那么花费时间 - 您最好使用SqlCommand.Timeout
属性。这将取消基础操作。
尊重@ YuvalItzchakov的评论。他说在等待启动任务并等待同步完成任务时没有意义。你应该认真看看awaiting it。
Btw 20000毫秒不是2秒。这是20秒。