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