2015-03-25 57 views
0

對於異步我很新,我理解一些一般概念,但似乎無法解決幾個問題。如何在異步方法中使用不同類中的其他函數

我有以下ReceiveCallback:

public static void ReceiveCallback(IAsyncResult AR) 
    { 
     Socket CurrentSocket = (Socket)AR.AsyncState; 
     int DataReceived = 0; 

     try 
     { 
      DataReceived = CurrentSocket.EndReceive(AR); 
     } 
     catch (SocketException) 
     { 
      CurrentSocket.Close(); 
      return; 
     } 

     byte[] receivedBuffer = new byte[DataReceived]; 
     Array.Copy(Buffer, receivedBuffer, DataReceived); 
     strReceived = Encoding.ASCII.GetString(receivedBuffer); // We are saving the latest receivedBuffer in a string. 
     new MainWindow().Process(); // We are accessing a function in the MainWindow class 
     receiveDone.Set(); 
     CurrentSocket.BeginReceive(Buffer, 0, BufferSize, SocketFlags.None, ReceiveCallback, CurrentSocket); 
    } 

這裏的 「過程()」 代碼:

public void Process() 
    { 
     lblReceived.Text = ClientSocket.strReceived; // Trying to set what we received in a label.. 
    } 
  1. 就行:「新主窗口()方法(); 「, 我收到以下異常:」其他信息:調用線程必須是STA,因爲許多UI組件都需要這個。「 我搜索了,並理解爲什麼它給了我例外,但幾個代碼沒有爲我工作。

  2. 該標籤不會改變,我知道我正在創建一個MainWindow的新實例,這就是爲什麼什麼都沒有顯示,但我正在尋找我如何通過使用新實例來更改標籤的示例。

+2

提示 - 請勿在標題中添加標籤 - 違反如此的規則 – Muds 2015-03-25 12:27:54

+0

正如狀態所示,「MainWindow」是一個主窗口,因此它必須是唯一的。有**可以只有一個主窗口。如果你想從異步創建窗口稱爲回調,那麼你的設計出現問題。這是一種糟糕的做法,請重新考慮這一點。 – dymanoid 2015-03-25 12:56:19

+0

「創建窗口」?我只是創建一個對象來訪問在MainWindow類中找到的函數。 Asychnronous方法只是在單獨的課程上創建。 – 2015-03-25 14:14:22

回答

0

不幸的是,沒有a good, minimal, complete code example沒有辦法知道你的問題提供一個確切的答案足夠的上下文。

但一些一般性意見,可以提出:

  1. 最重要的是,如果你需要訪問一個類的實例成員,這是因爲(至少,應該是因爲…現在永遠是,如果類是精心設計的)那裏已經是您需要使用的那個類的一個實例。即那個例子你需要訪問的狀態。

因此,創建一個類的全新實例只是因爲你無法以其他方式訪問類(喜歡這裏的Process()方法)的一些實例成員總是錯誤的做法。

相反,您需要提供對已存在的具有您需要訪問的狀態的實例的訪問權限。

  • 只是使基於所述比特和您的代碼被提供的片寬的猜測,我假設ReceiveCallback()方法實際上是在你MainWindow類聲明。如果這個猜測是正確的,那麼對代碼最明顯的修正就是簡單地將ReceiveCallback()方法設爲非static。即從方法聲明中刪除static。完成後,您只需直接撥打Process(),而不是首先創建MainWindow的新實例。
  • 現在,在這樣做時,您可能(或可能不會)發現提供方法作爲原始I/O操作的參數需要修復。再次,因爲你沒有提供一個好的代碼示例,所以不可能說出是否或如何完成。但是我提到它只是爲了讓您不要在宣言中刪除static後立即放棄該想法。


    當然,我的猜測可能是錯誤的。在這種情況下,一種選擇是將您的MainWindow實例的引用作爲I/O操作的狀態對象。再說一遍,如果沒有一個好的代碼示例,那麼這個工作如何是不可能的,但基本思想是將它作爲Socket.BeginReceive()方法的最後一個參數(任何過載),然後從ReceiveCallback()方法中的IAsyncResult.AsyncState屬性中檢索它。


    注:以上只是解決你所得到的具體例外,創建一個新的MainWindow實例只是保證是錯誤的做法。由於I/O操作很可能會在UI線程之外完成,因此您仍然遇到與處理該問題相關的問題(例如,需要在訪問UI本身的代碼上調用Dispatcher.Invoke())。但一次只能一步。在轉到下一個問題之前,先解決緊急問題。

    如果以上都不是很有幫助,那麼請修復您的問題,以便它包含一個很好的代碼示例,通過它可以提供實際的準確答案。

    +0

    非常感謝有用的信息。你說我可以刪除ReceiveCallback()中的靜態。這樣做有缺點嗎?因爲如果根據MSDN我沒有弄錯,這些CallBack必須是靜態的。我會繼續嘗試一些您提到的解決方案。謝謝:) 編輯:ReceiveCallback()在程序的命名空間內的一個單獨的類上找到。說,在MainWindow.xaml.cs中找到MainWindow,在ClientSocket.cs中找到ReceiveCallback() – 2015-03-25 16:09:49

    +0

    在MainWindow類中顯式使用ReceiveCallback()並在ReceiveCallback()方法中刪除靜態關鍵字修復了問題。 爲了解決線程問題,我使用了下面的代碼; http://stackoverflow.com/a/21539361/4135053 – 2015-03-25 16:24:41

    +0

    @OhHey:「這些CallBacks必須是靜態的」 - 不確定你在MSDN中看到了什麼讓你認爲是這種情況,但這絕對不是真的。回調可以是正確簽名的任何委託實例,並且該委託的目標可以是靜態或非靜態的。使用非靜態方法沒有任何固有的缺點,事實上,使用非靜態方法使訪問實例成員更加容易。 :) – 2015-03-25 17:06:31

    相關問題