c# - 从任务中调用函数

标签 c# task func

我正在编写一个自定义报告工具,允许用户创建一些非常广泛的查询。我想为此添加一个超时,这样如果用户创建的东西最终会运行很长时间,整个系统就不会停止。我想到了这个:

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/

相关文章:

c# - 任务的延续(由 async/await 构建)在 WPF 应用程序的主线程上运行,但在控制台应用程序的子线程上运行

c# - 在作为参数传递的对象上调用作为参数传递的方法

c# - 从邻接表创建树的最有效方法

c# - 不能在 Entity Framework 中使用土耳其语字符

c# - 如何对记录进行分组并仅检索具有前 N 条记录的第一组

c# - 以 Func 为键的字典

linq - .net core - 将函数列表与单个函数组合或合并到单个函数

c# - 如何将 C# double[] 传递给需要常量 double* pArr 的 C++ 函数? C++, C#

.net - 任务继续 (OnlyOnFaulted) 仍然无法观察到异常

multithreading - Ada任务和终止