[英]Calling a Func From a Task
我正在编写一个自定义报告工具,允许用户创建一些非常广泛的查询。 我想为此添加一个超时,这样如果用户创建的东西最终会运行很长时间,整个系统就不会停止。 我想出了这个:
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>。 有什么方法可以解决这个问题吗?
在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的评论。 他说在等待启动任务并等待同步完成任务时没有意义。 你应该认真看待等待它 。
Btw 20000毫秒不是2秒。 这是20秒。
感谢大家的反馈。 我现在的解决方案如下:
public List<List<SimpleDisplayField>> FindReport(int reportId)
{
var report = GetReportById(reportId);
return (report.BidType == "LOB")
? RunReportAsync(FindLOBReport, report).Result
: RunReportAsync(FindFWOReport, report).Result;
}
private async Task<List<List<SimpleDisplayField>>> RunReportAsync(Func<CustomReport, List<List<SimpleDisplayField>>> method, CustomReport report)
{
var task = await Task.Factory.StartNew(() => method.DynamicInvoke(report));
return (List<List<SimpleDisplayField>>)task;
}
在FindLOB / FWOReport中我使用它来超时查询:
using (TRACSEntities db = new TRACSEntities())
{
db.Database.CommandTimeout = 60;
var query = // and so on
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.