不能返回带线程的DataTable

本文关键字:DataTable 线程 返回 不能 | 更新日期: 2023-09-27 18:04:56

我试图使用线程从另一个类返回数据表,但线程没有返回数据表。当不使用线程时,它工作得很好。

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());
        }
    }
}

不能返回带线程的DataTable

您的代码中有一些地方出了问题。

首先,你面临的问题是,你正在启动一个线程,但不是让它完成,而是立即试图获得结果。您需要使用某种机制来知道线程何时完成,以便能够在UI线程上继续工作。使用th.Join()不是最好的方法,因为它在加载数据表时锁定了UI线程。

现在最简单的方法就是使用任务并行库(TPL)来为你固定和管理线程。

在我向你展示如何做之前,我只想评论一些其他的事情。

在你的reatail类你有order_dt变量作为一个字段,你只实例化它一次。这意味着在调用loadAllOrder的每个地方,您将获得对同一表的引用,并且该表将继续被越来越多的重复记录填充。您需要移动loadAllOrder方法中的字段来防止这种情况。

同样,在RecieveOrder中,您通过实例化一个新的DataTable来声明dy,但随后您在调用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());
        }
    }
}

您试图访问返回值,甚至在您的线程完成执行之前。在开始使用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());
        }
    }
}