C#事件处理(与Java相比)

Ric*_*ton 11 c# delegates event-handling

我目前正在使用delagates在C#中很难理解和实现事件.我习惯了Java的做事方式:

  1. 为侦听器类型定义一个接口,该接口包含许多方法定义
  2. 如果我对侦听器中定义的所有事件不感兴趣,请为该接口定义适配器类以使事情更容易
  3. 在类中定义Add,Remove和Get []方法以引发事件
  4. 定义受保护的fire方法来执行循环遍历添加的侦听器列表并调用正确方法的脏工作

这个我理解(并且喜欢!) - 我知道我可以在c#中完全相同,但似乎有一个新的(更好的?)系统用于c#.在阅读了无数教程解释c#中代表和事件的使用后,我仍然无法真正了解正在发生的事情:S


简而言之,对于以下方法,我将如何在c#中实现事件系统:

void computerStarted(Computer computer);
void computerStopped(Computer computer);
void computerReset(Computer computer);
void computerError(Computer computer, Exception error);
Run Code Online (Sandbox Code Playgroud)

^上面的方法取自我曾经制作的Java应用程序,我试图将其移植到c#.

非常感谢!

Jon*_*eet 16

您将创建四个事件,以及用于引发它们的方法,以及一个新的基于EventArgs的类来指示错误:

public class ExceptionEventArgs : EventArgs
{
    private readonly Exception error;

    public ExceptionEventArgs(Exception error)
    {
         this.error = error;
    }

    public Error
    {
         get { return error; }
    }
}

public class Computer
{
    public event EventHandler Started = delegate{};
    public event EventHandler Stopped = delegate{};
    public event EventHandler Reset = delegate{};
    public event EventHandler<ExceptionEventArgs> 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 OnError(Exception e)
    {
        Error(this, new ExceptionEventArgs(e));
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,类将使用方法或匿名函数订阅事件:

someComputer.Started += StartEventHandler; // A method
someComputer.Stopped += delegate(object o, EventArgs e)
{ 
    Console.WriteLine("{0} has started", o);
};
someComputer.Reset += (o, e) => Console.WriteLine("{0} has been reset");
Run Code Online (Sandbox Code Playgroud)

有关上述内容的一些注意事项:

  • OnXXX方法受到保护,因此派生类可以引发事件.这并不总是必要的 - 按照您认为合适的方式进行.
  • delegate{}每个事件的声明部分只是一招,以避免做一个空检查.它为每个事件订阅了一个no-op事件处理程序
  • 事件声明是类似字段的事件.实际创建的是变量事件.在课堂上你看到变量; 在课外,你会看到这个事件.

有关事件的更多详细信息,请参阅我的活动/代表文章.

  • 我会说你只希望看到空检查,因为你不习惯这种模式 - 一旦你知道它就在那里以及为什么,我相信它会使它更具可读性.这当然是我的经历.在我看来,可读性的好处值得微小的额外内存占用(续) (2认同)

jop*_*jop 5

你必须为此定义一个委托

public delegate void ComputerEvent(object sender, ComputerEventArgs e);
Run Code Online (Sandbox Code Playgroud)

ComputerEventArgs将定义如下:

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)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

触发事件的类将具有以下内容:

public YourClass
{
    ...
    public event ComputerEvent ComputerStarted;
    public event ComputerEvent ComputerStopped;
    public event ComputerEvent ComputerReset;
    public event ComputerEvent ComputerError;
    ...
}
Run Code Online (Sandbox Code Playgroud)

这是您为事件分配处理程序的方法:

YourClass obj = new YourClass();
obj.ComputerStarted += new ComputerEvent(your_computer_started_handler);
Run Code Online (Sandbox Code Playgroud)

你的处理程序是:

private void ComputerStartedEventHandler(object sender, ComputerEventArgs e)
{
   // do your thing.
}
Run Code Online (Sandbox Code Playgroud)