为何以及何时使用事件?

时间:2010-06-29 09:34:16

标签: c# .net events

在我的个人项目中,我从未使用过Event.I从未感觉到它是必要的。特别是使用事件会产生一些关于限制具有相同参数的方法的问题,这就是为什么我没有使用它。什么是好处使用它 ?什么时候和我们需要的地方?

编辑:对于封闭源库,使用事件更多?因为我们无法将任何方法附加到现有的闭源方法中,所以Events会帮助我们解决这个问题吗?因为在开源中,我们可以很容易地将我们的方法添加到方法的末尾。

5 个答案:

答案 0 :(得分:5)

哦,我遇到了同样的问题。我理解事件的概念,因为我在JavaScript中大量使用它们,但我无法证明在C#应用程序中使用事件是正确的。我的意思是,我使用了服务器OnClick等,但我无法理解为什么我会在其他任何地方使用事件。

实际上有趣的故事,因为当我在ORPG游戏中工作时,我学到了很多东西。请考虑以下代码:

class Player
{
    private int health;
    public int Health
    {
        get
        {
            if (health <= 0)
            {
                Die();
            }

            return health;

        }

        set
        {
            health = value;
        }
    }

    public void Die()
    {
        // OMG I DIED, Call bunch of other methods:
        // RemoveFromMap();
        // DropEquipment(); etc
    }
}

有道理,对吗?玩家没有健康,所以我打电话给Die()。然后,Die方法正在做任何应该做的事情 - 杀死玩家。

当我想在ORPG游戏的服务器和客户端应用程序中重用此类时,我的问题就开始了。很容易注意到Die()方法应该做不同的事情,取决于执行'杀戮'的位置 - 在服务器上它应该更新各种不同的数据 - 在客户端它应该用图形做一些事情。

此外 - 如果我希望Die()方法执行不同的操作,具体取决于播放器的类型,该怎么办?与计算机/人工智能控制的玩家(NPC)相比,所有用户控制的玩家在被杀后都应该做不同的事情。

所以,我被迫使用事件:

class Player
{
    public event DieHandler Die;
    public delegate void DieHandler(Player sender, EventArgs e);
    public virtual void OnDie(EventArgs e)
    {
        if (Die != null)
            Die(this, e);
    }

    private int health;
    public int Health
    {
        get
        {
            if (health <= 0)
            {
                onDie(new EventArgs());
            }

            return health;

        }

        set
        {
            health = value;
        }
    }
}

现在,当我创建新玩家时,我可以将任何方法分配给其DieHandler

Player player = new Player("Joe");
player.Die += Client.Players.PlayerDie;

Player npc = new Player("Cookie Monster");
npc.Die += Client.Npcs.NpcDie;

其中Client.Npcs.DieClient.Players.Die是以下之一:

public void NpcDie(Player sender, EventArgs e)
{
    //who hoo, I can be implemented differently
    //I can even check if sender.Health <= 0
}

public void PlayerDie(Player sender, EventArgs e)
{
}

正如您现在所看到的,我们已经灵活地将任何“匹配”方法附加到我们的Die处理程序。我们将Player对象作为sender属性和e中任何已定义的EventArgs发送。我们可以使用EventArgs发送其他信息,例如 - e.NameOfTheKillere.LastHitAtTime等等。最好的是您可以定义自己的EventArgs类,以便发送更多信息产生事件时的信息。

哇...这个帖子很长。我希望你现在明白。

再次 - 当您想要“告知外部世界”某个特定的对象状态并适当地处理此更改时,请在任何地方使用事件。它将使您的代码更灵活,更易于维护。

答案 1 :(得分:1)

好吧,当你需要观察者对你对象中发生的事件作出反应时:)

最明显的例子是UI组件 - 例如Button公开了点击按钮时触发的事件。

如果你没有任何自然感觉的东西,就像暴露事件一样,那么就不要使用它们。但是,如果您有任何其他方对对您的对象中发生的事情作出反应感兴趣的事情,您应该考虑事件 - 和/或Reactive Extensions框架。

答案 2 :(得分:1)

您无需使用它。但是,如果您要解决的问题需要它,它只是您最终会做的事情的捷径。但是,由于您使用的是具有快捷方式的C#.NET,因此最好使用它们。它更多C#ish。

答案 3 :(得分:1)

最明显的例子是,在处理GUI时,事件特别有用。您的应用程序用户通常会与代码的前端部分(本例中为图形界面)进行交互,而大多数逻辑都是“隐藏”的。

我确定你已经看过这个架构 - 你按下按钮,在后台“发生”某事,你会看到操作结果。您不需要知道究竟发生了什么,您只对应用程序窗口中显示的“您的票已被预订”字符串感兴趣。

与用户界面相同的故事。在大多数情况下,它不需要知道(也不应该)应用逻辑是如何实现的,或者它是做什么的。它是在那里呈现结果并与用户交互。

在.NET中如何运作?考虑延续票务预订示例,部分说TicketBooker类:

public event Action BookingSuccessful;

public void BookTicket()
{
    // lot of complex steps that should run in background
    this.ValidateInputData();
    this.GetTicketInfo();
    this.CheckUserInfo();
    this.SendDataToOperator();
    this.WithdrawMoney(); 
    // ...and perhaps lot more stuff you might want to do 
    // in order to book ticket
    if (booked)
    {
        // we're done: let's raise event which will 
        // notify all interested observers 
        this.BookingSuccessful();
    }
}

正如您所看到的,BookTicket方法可能需要很长时间才能完成,可能有许多复杂的步骤,其中大多数 - 作为用户 - 我们不想知道。无论我们是否预订,我们都需要这些信息。

知道这一点,我们不希望用户等待挂起的应用程序因为预订了机票。用户仍然应该能够与它进行交互(当然在某种程度上)。因此,用户界面类想要订阅TicketBooker类事件。

TicketBooker tb = new TicketBooker();
tb.BookingSuccessful += this.ShowSuccessMessage;

// ... somewhere here we call tb.BookTicket() method to run in background
// once it completes (with success), it will raise BookingSuccessful event
// which will cause ShowSuccessMessage to execute, as we subscribed it

public void ShowSuccessMessage()
{
    // simply display success message in interface, eg. by setting label text
}

当然,比这个简单的例子要大得多。事件有助于将应用程序表示层与数据模型/业务逻辑分离,它们处理感兴趣对象关于对象更改的通知等。

首先,您可以在MSDN上查看本教程:Events Tutorial

检查模型 - 视图 - 控制器模式的工作原理也可以提供更好的理解:MVC

与往常一样,SO在这个主题上充满了资源,只是搜索标记为events & .net的问题。

答案 4 :(得分:0)

当服务器可以调用客户端的方法时,事件用于回调。这样的选项不仅存在于c#中(例如c ++中的函数指针)。因为你可能不会使用事件来构建你的代码来避免它们。我建议更好地了解他们,了解他们的优势。