2016-09-01 5 views
1

スレッドを使用して別のクラスからDataTableを返そうとしていますが、スレッドが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

スレッドは性質上非同期です。あなたは彼らが返すデータにアクセスする前に、実行のフィニッシュラインを知る必要があります。 – RBT

答えて

2

スレッドの実行が終了する前でも戻り値にアクセスしようとしています。 foreachループを使用してテーブルの行を反復処理する前に、th.Join();を実行する必要があります。あなたがそれを行う方法は次のとおりです。

+0

ありがとうございました。 – mofidul

+1

これはトリックですが、実際には同じスレッド上でloadメソッドを呼び出すよりも優れていません。実際には、スレッドを作成するオーバーヘッドのために悪化します。 – Enigmativity

+0

@enigmativity true。スレッドが終了するのを待っている間、UIをハングアップします。レスポンシブなUI活用のために、代わりにTPLが良い選択肢になるでしょう。 – RBT

2

コードに間違ったことがいくつかあります。

あなたが直面している問題で始めるには、スレッドを開始していることですが、終了することを許可する代わりにすぐに結果を取得しようとしています。スレッドが終了したときにUIスレッドで作業を続行できるようにするには、何らかのメカニズムを採用する必要があります。 th.Join()を使用することは、データテーブルがロードされている間にUIスレッドをロックするため、最良の方法ではありません。

最近では最も簡単なことは、タスク並列ライブラリ(TPL)を使用してスレッドをピンして管理することです。

前に、私が他のいくつかのことについてどのようにコメントしたかったかを説明します。

reatailクラスでは、フィールドとして変数order_dtがあり、それを1回だけインスタンス化します。これは、loadAllOrderが呼び出されたすべての場所で、同じテーブルへの参照を取得することを意味し、そのテーブルにはさらに重複したレコードがいっぱいになります。これを防ぐには、loadAllOrderメソッド内でフィールドを移動する必要があります。

また、RecieveOrderにあなたはインスタンス化新しいDataTabledyを宣言しますが、その後、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()); 
     } 
    } 
} 
関連する問題