对象可以订阅自己的事件以更改内部数据是否可以?

时间:2018-09-04 21:12:34

标签: c# events event-handling

正如标题所述,对象订阅自己的事件是否合理?

public class Player
{
    private int team;

    public Action<int> TeamChanged { get; set; }

    public Player(int startingTeam)
    {
        team = startingTeam;

        TeamChanged += OnTeamChanged; // subscribe to my own event
    }

    private void OnTeamChanged(int newTeam)
    {
        team = newTeam;
    }
}

// later during the match:
public void ShuffleTeam()
{
    player.TeamChanged(GetRandomTeam());
}

似乎比具有一个额外的ChangeTeam()函数(它调用事件本身)要简洁得多。但由于某种原因,也会感到不对。

1 个答案:

答案 0 :(得分:2)

您似乎正在颠倒理解事件。事件发生时会触发事件,您不会触发事件来发生某事;您调用一个方法。

以您为例,当Team属性更改时,您将触发事件。您不会触发事件来改变团队。您需要更换团队吗?实施一个精确地做到这一点的公共方法或属性设置器,并让想要改变团队的人改变。

此外,将一个事件声明为一个事件,将其声明为一个委托。解决问题的正确方法是:

public class Player
{
    public event Action<int> TeamChanged;

    private int team;
    public int Team 
    {
        get { return team; }
        set 
        {
            if (value != team) {
                team = value;
                OnTeamChanged(team); } 
        } 
    }

    public Player(int startingTeam)
    {
        team = startingTeam; 
    }

    private void OnTeamChanged(int newTeam)
    {
        TeamChanged?.Invoke(team);
    }
}

现在,任何需要对换队人员采取行动的消费者都可以订阅该事件。

您也可以跳过整个OnTeamChanged业务,并直接在属性设置器中引发事件,除非您正在考虑某种继承模型,在这种情况下,方法应为protected

总而言之,订阅一个自己的事件根本没有任何意义。事件驱动的设计非常有用,因为您无法控制或知道事件何时触发。用户按下鼠标按钮或关闭应用程序。通过在类本身中声明一个事件,您总是知道何时触发该事件,因此您必须在某个地方实现该调用,订阅该调用是荒谬的。