如何使用多线程.NET C#进行正确的封装 [英] How to make correct encapsulation with multithreading .NET C#

查看:387
本文介绍了如何使用多线程.NET C#进行正确的封装的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如您所见,我有两个课程. RfidReaderHardware在线程"th"中生成事件,但是Form在另一个线程中运行.如您所见,在形式上是否使用ListViewControl的Invoke方法.因此,问题是如何更改RfidReaderHardware以解决封装问题.

As you can see, I have two classes. RfidReaderHardware generates event in thread "th", but Form running at another thread. As you can see, in form if use Invoke method of ListViewControl. So, question is how to change RfidReaderHardware to resolve encapsulation problem.

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 ...
}

我们有示例代码,其中此事件正在使用

and we have example code, where this event is using

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

推荐答案

不确定是否确实需要解决此问题,让UI对象本身处理错误"线程上触发的事件不是缺陷.只要您知道它实际上是在错误的线程上触发的,那就是文档要求.

Not so sure there's any real need to fix this, having the UI object itself deal with the fact that event is fired on the "wrong" thread is not a flaw. As long as you know it is in fact fired on the wrong thread, a documentation requirement.

.NET具有解决此问题的通用机制,它在.NET Framework代码中的多个位置使用.您的RfidReaderHardware类构造函数可以复制 SynchronizationContext.Current 并将其存储在字段中.隐式假设对象是由在UI线程上运行的代码创建的.当您准备触发该事件并且复制的对象不为null时,可以使用其Post()或Send()方法.这自动使代码在UI线程上恢复.不管使用哪种特定的UI类库,例如,在WPF或Universal应用程序中,效果都一样.

.NET however has a general mechanism to solve this, it is used in several places inside the .NET Framework code. Your RfidReaderHardware class constructor can copy the value of SynchronizationContext.Current and store it in a field. With the implicit assumption that the object is created by code that runs on the UI thread. When you are ready to fire the event, and the copied object isn't null, you can then use its Post() or Send() method. Which automagically makes the code resume on the UI thread. Regardless of the specific UI class library that was used, works just as well in a WPF or Universal app for example.

一些示例代码,花费不多:

Some sample code, it doesn't take much:

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

这篇关于如何使用多线程.NET C#进行正确的封装的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆