简体   繁体   中英

C# EventHandler invoke doesn't always work

I have a class with the following code:

    public delegate void EventHandler(HMIEventArgs e);
    public event EventHandler OnEvent;

    private void ReadReg(RegisterMap register)
    {
        if (!_hmiConnected) return;
        var eventArgs = new HMIEventArgs();

        var handler = OnEvent;

        try
        {
            byte slaveId = 1;
            ushort startAddress = register.Register;

            eventArgs.Event = Events.GotData;
            eventArgs.IPAddress = _hostname;
            eventArgs.Name = register.FriendlyName;

            ushort[] val = _master.ReadHoldingRegisters(slaveId, startAddress, 1);
            eventArgs.Data = val[0];
            handler?.Invoke(eventArgs);

            // -------- THIS GETS PRINTED ------------
            Debug.WriteLine("Got data from " + _hostname + ":" + register.Register + "(" + register.FriendlyName + ") : " + val[0]);
            
        }
        catch (Exception err)
        {
            Debug.WriteLine(err.ToString());                
        }
    }

Several instances of this class are created in another class :

        new Thread(() =>
        {
            tasks.Add(Task.Factory.StartNew(() =>
            {
                _masters.Add(new HMIMaster().Connect(ipAddress, port).SetRegisters(registers));

                _masters.Last().OnEvent += HMIEvent;

                Debug.WriteLine(_masters.Count + " masters");
            }));

        }).Start();


    private static void HMIEvent(HMIEventArgs e)
    {

        // HOWEVER THIS SOMETIMES DOESN'T SHOW FOR 
        // ALL INSTANCES OF THE PREVIOUS CLASS

        Debug.WriteLine(">> in logger (" + e.IPAddress + " " + e.Event + ") >> " + e.Name + " :: " + e.Data);
        var handler = OnEvent;
        handler?.Invoke(e);
    }

Am I doing something wrong here?

I would use a static event to avoid registering every time on new instance and un-register on dispose (to void memory leaks). No locking is required in your case so I would simplify it like that:

(First class)

public static event EventHandler<HMIEventArgs> HMIEvent;
private void OnHMIEvent(HMIEventArgs e)
{
    HMIEvent?.Invoke(this, e);
}

private void ReadReg(RegisterMap register)
{
    ...
    OnHMIEvent(new HMIEventArgs()
    {
        Name = register.FriendlyName,
        Event = Events.GotData,
        IPAddress = _hostname,
        eventArgs.Data = val[0]
    });
    ...
}

(Second Class)


...
FirstClass.HMIEvent += FirstClass_HMIEvent; // Probably in your static constructor, register only once (unregister if required on disposal)
...

private void FirstClass_HMIEvent(object sender, HMIEventArgs e)
{
// (FirstClass)sender can be used here if required
}

By the way those two lines at your sample code should not be there (on your static HMIEvent method, you didn't provide us what is the OnEvent on your second class and you dont need to pass it on the handler var every time):

var handler = OnEvent;
handler?.Invoke(e);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM