从任务

时间:2015-04-28 20:14:30

标签: 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返回我的List&gt;。有什么方法可以解决这个问题吗?

1 个答案:

答案 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秒。