我正在编写一个自定义报告工具,允许用户创建一些非常广泛的查询。我想为此添加一个超时,这样如果用户创建的东西最终会运行很长时间,整个系统就不会停止。我想到了这个:
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 返回我的列表>。有什么办法可以解决这个问题吗?
最佳答案
在你的RunReport
方法,你实际上并没有调用 method
功能您正在重新调整 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
属性(property)。这将取消基础操作。
尊重@YuvalItzchakov 的评论。他说等待任务开始并同步完成是没有意义的。你应该认真看看awaiting it .
顺便说一句,20000 毫秒不是 2 秒。这是 20 秒。
关于c# - 从任务中调用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29929045/