C# event handling (compared to Java)

后端 未结 9 702
离开以前
离开以前 2020-12-23 23:23

I am currently having a hardtime understanding and implementing events in C# using delagates. I am used to the Java way of doing things:

  1. Define an interface f
相关标签:
9条回答
  • 2020-12-23 23:59

    there are several ways to do what you want. The most direct way would be to define delegates for each event in the hosting class, e.g.

    public delegate void ComputerStartedDelegate(Computer computer);
    protected event ComputerStartedDelegate ComputerStarted;
    public void OnComputerStarted(Computer computer)
    {
        if (ComputerStarted != null)
        {
            ComputerStarted.Invoke(computer);
        }
    }
    protected void someMethod()
    {
        //...
        computer.Started = true;  //or whatever
        OnComputerStarted(computer);
        //...
    }
    

    any object may 'listen' for this event simply by:

    Computer comp = new Computer();
    comp.ComputerStarted += new ComputerStartedDelegate(
        this.ComputerStartedHandler);
    
    protected void ComputerStartedHandler(Computer computer)
    {
        //do something
    }
    

    The 'recommended standard way' of doing this would be to define a subclass of EventArgs to hold the Computer (and old/new state and exception) value(s), reducing 4 delegates to one. In this case that would be a cleaner solution, esp. with an Enum for the computer states in case of later expansion. But the basic technique remains the same:

    • the delegate defines the signature/interface for the event handler/listener
    • the event data member is a list of 'listeners'

    listeners are removed using the -= syntax instead of +=

    0 讨论(0)
  • 2020-12-24 00:02

    The main difference is that in C# the events are not interface-based. Instead, the event publisher declares the delegate which you can think of as a function pointer (although not exactly the same :-)). The subscriber then implements the event prototype as a regular method and adds a new instance of the delegate to the event handler chain of the publisher. Read more about delegates and events.

    You can also read short comparison of C# vs. Java events here.

    0 讨论(0)
  • 2020-12-24 00:09

    Ok, FINAL clarification!: So this is pretty much the best I can do code-wise to implement those events?

       public class Computer {
    
            public event EventHandler Started;
    
            public event EventHandler Stopped;
    
            public event EventHandler Reset;
    
            public event EventHandler<BreakPointEvent> BreakPointHit;
    
            public event EventHandler<ExceptionEvent> Error;
    
            public Computer() {
                Started = delegate { };
                Stopped = delegate { };
                Reset = delegate { };
                BreakPointHit = delegate { };
                Error = delegate { };
            }
    
            protected void OnStarted() {
                Started(this, EventArgs.Empty);
            }
    
            protected void OnStopped() {
                Stopped(this, EventArgs.Empty);
            }
    
            protected void OnReset() {
                Reset(this, EventArgs.Empty);
            }
    
            protected void OnBreakPointHit(int breakPoint) {
                BreakPointHit(this, new BreakPointEvent(breakPoint));
            }
    
            protected void OnError(System.Exception exception) {
                Error(this, new ExceptionEvent(exception));
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-24 00:11

    Thank you all so much for your answers! Finally I'm starting to understand what is going on. Just one thing; It seems that if each event had a different number/type of arguments I'd need to create a different :: EventArgs class to deal with it:

    public void computerStarted(Computer computer);
    public void computerStopped(Computer computer);
    public void computerReset(Computer computer);
    public void breakPointHit(Computer computer, int breakpoint);
    public void computerError(Computer computer, Exception exception);
    

    This would require three classses to deal with the events!? (Well two custom, and one using the default EventArgs.Empty class)

    Cheers!

    0 讨论(0)
  • 2020-12-24 00:12

    First of all, there is a standard method signature in .Net that is typically used for events. The languages allow any sort of method signature at all to be used for events, and there are some experts who believe the convention is flawed (I mostly agree), but it is what it is and I will follow it for this example.

    1. Create a class that will contain the event’s parameters (derived from EventArgs).
    public class ComputerEventArgs : EventArgs 
    {
      Computer computer; 
      // constructor, properties, etc.
    }
    
    1. Create a public event on the class that is to fire the event.
        class ComputerEventGenerator  // I picked a terrible name BTW.
        {
          public event EventHandler<ComputerEventArgs> ComputerStarted;
          public event EventHandler<ComputerEventArgs> ComputerStopped;
          public event EventHandler<ComputerEventArgs> ComputerReset;
        ...
        }
    
    1. Call the events.
        class ComputerEventGenerator
        {
        ...
          private void OnComputerStarted(Computer computer) 
          {
            EventHandler<ComputerEventArgs> temp = ComputerStarted;
            if (temp != null) temp(this, new ComputerEventArgs(computer)); // replace "this" with null if the event is static
          }
         }
    
    1. Attach a handler for the event.
        void OnLoad()
        {
          ComputerEventGenerator computerEventGenerator = new ComputerEventGenerator();
          computerEventGenerator.ComputerStarted += new  EventHandler<ComputerEventArgs>(ComputerEventGenerator_ComputerStarted);
        }
    
    1. Create the handler you just attached (mostly by pressing the Tab key in VS).
        private void ComputerEventGenerator_ComputerStarted(object sender, ComputerEventArgs args)
        {
          if (args.Computer.Name == "HAL9000")
             ShutItDownNow(args.Computer);
        }
    
    1. Don't forget to detach the handler when you're done. (Forgetting to do this is the biggest source of memory leaks in C#!)
        void OnClose()
        {
          ComputerEventGenerator.ComputerStarted -= ComputerEventGenerator_ComputerStarted;
        }
    

    And that's it!

    EDIT: I honestly can't figure out why my numbered points all appear as "1." I hate computers.

    0 讨论(0)
  • 2020-12-24 00:18

    You'll have to define a single delegate for that

    public delegate void ComputerEvent(object sender, ComputerEventArgs e);
    

    ComputerEventArgs would be defined like this:

    public class ComputerEventArgs : EventArgs
    {
        // TODO wrap in properties
        public Computer computer;
        public Exception error;
    
        public ComputerEventArgs(Computer aComputer, Exception anError)
        {
            computer = aComputer;
            error = anError;
        }
    
        public ComputerEventArgs(Computer aComputer) : this(aComputer, null)
        {
        }
    }
    

    The class that fires the events would have these:

    public YourClass
    {
        ...
        public event ComputerEvent ComputerStarted;
        public event ComputerEvent ComputerStopped;
        public event ComputerEvent ComputerReset;
        public event ComputerEvent ComputerError;
        ...
    }
    

    This is how you assign handlers to the events:

    YourClass obj = new YourClass();
    obj.ComputerStarted += new ComputerEvent(your_computer_started_handler);
    

    Your handler is:

    private void ComputerStartedEventHandler(object sender, ComputerEventArgs e)
    {
       // do your thing.
    }
    
    0 讨论(0)
提交回复
热议问题