2015-11-07 35 views
2

正如你所看到的,我有兩個類。 RfidReaderHardware在線程「th」中生成事件,但在另一個線程上運行Form。正如你所看到的那樣,如果使用ListViewControl的Invoke方法。所以,問題是如何更改RfidReaderHardware來解決封裝問題。如何正確封裝多線程.NET C#

public class RfidReaderHardware : IDisposable 
{ 
    public event EventHandler<RfidReaderEventArgs> OnNewPackage; 
    Thread th; 
    //This method will be called from thread "th" 
    private void FireNewPackageEvent(UHFPackage package) 
    { 
     ... code ... 
    } 
    ... some code ... 
} 

,我們有示例代碼,此事件的使用

public partial class PassageForm : Form 
{ 
    RfidReaderHardware RfidReader = new RfidReaderHardware(...); 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     RfidReader.OnNewPackage += NewRfidPackage; 
    } 
    //not sure, but i think it's running in thread "th" 
    private void NewRfidPackage(Object o, RfidReaderEventArgs e) 
    { 
     ListViewItem item = new ListViewItem(); 
     //from point of encapsulation view it's wrong as you know 
     CPackageList.Invoke(new Action(() => {CPackageList.Items.Add(item); })); 
    } 
} 

回答

0

不確定是否有任何真正的需要解決這個問題,讓UI對象本身處理事件在「錯誤」線程上被觸發的事實不是一個缺陷。只要你知道它實際上是在錯誤的線程上觸發的,一個文檔要求。

但是.NET有一個通用的機制來解決這個問題,它在.NET Framework代碼中的幾個地方使用。您的RfidReaderHardware類構造函數可以複製SynchronizationContext.Current的值並將其存儲在一個字段中。隱含假設該對象是由在UI線程上運行的代碼創建的。準備好引發事件並且複製的對象不爲空時,可以使用其Post()或Send()方法。它自動使代碼在UI線程上恢復。無論使用什麼特定的UI類庫,例如,在WPF或通用應用程序中都可以正常工作。

一些示例代碼,它不會花費太多:

public class RfidReaderHardware { 
    public event EventHandler Received; 

    public RfidReaderHardware() { 
     syncContext = System.Threading.SynchronizationContext.Current; 
    } 

    protected void OnReceived(EventArgs e) { 
     if (syncContext == null) FireReceived(e); 
     else syncContext.Send((_) => FireReceived(e), null); 
    } 

    protected void FireReceived(EventArgs e) { 
     var handler = Received; 
     if (handler != null) Received(this, e); 
    } 

    private System.Threading.SynchronizationContext syncContext; 
} 
1

的問題是如何改變RfidReaderHardware解決封裝問題

其實沒有封裝問題。根據定義,事件源與用戶之間的關係是一對多關係,因此源不能爲特定用戶「封裝」邏輯。用戶選擇如何處理通知。人們可以忽略它,或者立即處理它,或者像你的情況一樣在UI線程上同步處理它(使用Control.Invoke)或異步處理(使用Control.BeginInvoke)。

+0

我認爲,開發商不應該想怎麼另一個類的作品。這就是理由,爲什麼我做這件事。奇怪的定義你被發現:)。我瞭解一對多的關係,但有什麼區別? –

+0

@NikolayChernov我可以很容易地爲你提供漢斯發佈的內容,但是從OOP的角度來看它是錯誤的,因爲它違反了SR(單一責任)原則。事件來源是提高事件。所以我留在我的答案。你的問題是關於封裝原則,如果你只想自動在另一個線程上分派事件,你不應該這樣制定它。 –