我正在尝试使用线程从另一个类返回DataTable,但线程没有返回DataTable。虽然不使用该线程,但它可以正常工作。
public class reatail
{
DataTable order_dt = new DataTable();
public DataTable loadAllOrder()
{
OleDbConnection co = new OleDbConnection();
co.ConnectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + sd + "bowoni.accdb";
string loadAll = "select * from allorder";
co.Open();
OleDbCommand cc = new OleDbCommand(loadAll, co);
OleDbDataAdapter ad = new OleDbDataAdapter(cc);
ad.Fill(order_dt);
return order_dt;
}
}
public partial class RecieveOrder : Form
{
DataTable dy = new DataTable();
reatail r = new reatail();
Thread t;
public void storeToStock()
{
//DataTable dy = new DataTable();
Thread th=new Thread(()=>dy=r.loadAllOrder());
th.Start();
foreach(DataRow row in dy.Rows)
{
MessageBox.Show(row[0].ToString());
}
}
}
答案 0 :(得分:2)
您尝试在线程执行完毕之前访问返回值。在开始使用foreach循环迭代表中的行之前,您需要执行th.Join();
。以下是如何做到这一点:
public partial class RecieveOrder : Form
{
DataTable dy = new DataTable();
reatail r = new reatail();
Thread t;
public void storeToStock()
{
//DataTable dy = new DataTable();
Thread th=new Thread(()=>dy=r.loadAllOrder());
th.Start();
//wait for the thread to finish its execution and get the data from backend DB.
th.Join();
//now iterate the rows retrieved from DB
foreach(DataRow row in dy.Rows)
{
MessageBox.Show(row[0].ToString());
}
}
}
答案 1 :(得分:2)
您的代码中存在一些问题。
首先要解决的问题是你正在开始一个线程,但不是让它完成,而是立即尝试获得结果。您需要使用某种机制来了解线程何时完成才能在UI线程上继续工作。使用th.Join()
不是最好的方法,因为它在加载数据表时锁定了UI线程。
最简单的事情是使用任务并行库(TPL)为您设置和管理线程。
在我告诉你我如何评论其他几件事之前。
在reatail
班级中,您将order_dt
变量作为字段,并且只将其实例化一次。这意味着在loadAllOrder
被调用的每个地方,您将获得对同一个表的引用,并且该表将继续填充越来越多的重复记录。您希望在loadAllOrder
方法中移动字段以防止这种情况。
另外,在RecieveOrder
中,您通过实例化新的dy
来声明DataTable
,但随后您通过调用loadAllOrder
重新分配该变量。这是一个小浪费。保持代码清洁并避免创建不必要的对象要好得多。
所以你最好这样做:
public class reatail
{
public DataTable loadAllOrder()
{
DataTable order_dt = new DataTable();
OleDbConnection co = new OleDbConnection();
co.ConnectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + sd + "bowoni.accdb";
string loadAll = "select * from allorder";
co.Open();
OleDbCommand cc = new OleDbCommand(loadAll, co);
OleDbDataAdapter ad = new OleDbDataAdapter(cc);
ad.Fill(order_dt);
return order_dt;
}
}
public partial class RecieveOrder : Form
{
DataTable dy;
reatail r = new reatail();
public void storeToStock()
{
Task
.Run(() => r.loadAllOrder())
.ContinueWith(t =>
{
dy = t.Result;
foreach (DataRow row in dy.Rows)
{
MessageBox.Show(row[0].ToString());
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
}
这不会锁定UI,但允许加载在后台运行。
可能更简单的替代方法是使用async
/ await
。您的storeToStock
可能非常简单:
public partial class RecieveOrder : Form
{
DataTable dy;
reatail r = new reatail();
public async void storeToStock()
{
dy = await Task.Run(() => r.loadAllOrder());
foreach (DataRow row in dy.Rows)
{
MessageBox.Show(row[0].ToString());
}
}
}