为什么在没有async / await的情况下使用Dapper QueryAsync <t>时抛出TaskCanceledException?

时间:2016-09-01 19:04:43

标签: c# async-await task dapper

为什么在此方法上调用.Result会导致TaskCanceledException:

public Task<IEnumerable<object>> GetAsync()
{
    using (var conn = new SqlConnection("connectionString"))
    {
        return conn.QueryAsync<object>("select * from objects");
    }
}

但是在此方法上调用.Result可以起作用:

public async Task<IEnumerable<object>> GetAsync()
{
    using (var conn = new SqlConnection("connectionString"))
    {
        return await conn.QueryAsync<object>("select * from objects");
    }
}

第二种方法正在使用async\await个关键字。

2 个答案:

答案 0 :(得分:6)

第一种方法启动查询(调用private JButton quest; public Beginner() { int n = 10; // no of JButtons int radius = 200; Point center = new Point(250, 250); double angle = Math.toRadians(360 / n); List<Point> points = new ArrayList<Point>(); points.add(center); for (int i = 0; i < n; i++) { double theta = i * angle; int dx = (int) (radius * Math.sin(theta)); int dy = (int) (radius * Math.cos(theta)); Point p = new Point(center.x + dx, center.y + dy); points.add(p); } draw(points); } public void draw(List<Point> points) { JPanel panels = new JPanel(); SpringLayout spring = new SpringLayout(); // Layout used int count = 1; for (Point point : points) { quest = new JButton("Question " + count); quest.setForeground(Color.BLUE); Font fonte = new Font("Script MT Bold", Font.PLAIN, 20); quest.setFont(fonte); add(quest); count++; spring.putConstraint(SpringLayout.WEST, quest, point.x, SpringLayout.WEST, panels); spring.putConstraint(SpringLayout.NORTH, quest, point.y, SpringLayout.NORTH, panels); setLayout(spring); panels.setOpaque(false); panels.setVisible(true); panels.setLocation(10, 10); add(panels); // action Listener to be set on individual buttons quest.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent a) { if (quest.equals(points.get(5))) ; String c = "Hello!"; JOptionPane.showMessageDialog(null, c); } }); } } ),然后它处理QueryAsync,然后返回表示该查询的任务。该任务已取消,因为SqlConnection在完成之前已被处置。

第二种方法启动查询(调用SqlConnection),异步等待该查询完成,然后处理QueryAsync。从第二个方法返回的任务表示该方法的完成。

有关SqlConnection / async的详情,请参阅my blog

另外,您不应该使用await的异步方法;你应该使用Result代替。

答案 1 :(得分:2)

第一个方法抛出异常的原因是因为从方法返回Task时SqlConnection对象超出了范围。

第二种方法有效的原因是因为async&amp; await关键字模拟一个闭包,因为编译器将方法包装在幕后的状态机结构中。这最终使SqlConnection保持在范围内。我不会比这更进一步,因为细节有点复杂,并且因编译器而异。

为了能够在没有async / await关键字的情况下返回任务,您需要传入SqlConnection,以便在返回任务时它仍然在范围内:

public Task<IEnumerable<object>> GetAsync(SqlConnection conn)
{
    return conn.QueryAsync<object>("select * from objects");
}     

更新#1(回应评论)

为什么它与范围和闭包有关:

SqlConnection语句中的using实例化,将其范围限制为using块。因此,当第一个方法离开using块并返回任务时,SqlConnection超出范围并在任务完成之前被处置。在第二种方法中,async/await关键字将使编译器在幕后创建struct,并将异步方法的局部变量存储为该结构中的字段,以便可以使用它们在任务完成时的回调(await下面的代码)中。这类似于在幕后实施 closures 的方式。

相关问题