C# 在C中使用事件处理程序#

C# 在C中使用事件处理程序#,c#,eventhandler,C#,Eventhandler,我试图观察c#中的一个值,并在它发生变化时触发一个函数。根据阅读的例子,我有: //事件观察者 private int _currentFrame =1; public event System.EventHandler FrameChanged; protected virtual void OnFrameChanged() { if (FrameChanged != null) FrameChanged(this, EventArgs.Empty); } public int A

我试图观察c#中的一个值,并在它发生变化时触发一个函数。根据阅读的例子,我有:

//事件观察者

private int _currentFrame =1;
public event System.EventHandler FrameChanged;

protected virtual void OnFrameChanged()
{
    if (FrameChanged != null) FrameChanged(this, EventArgs.Empty);
}

public int Age
{
    get
    {
        return _currentFrame;
    }

    set
    {
        //#3
        _currentFrame = value;
        OnFrameChanged();
    }
}
在我的主要职责中:

_currentFrame += _currentFrame;
据我所知,这应该会触发事件观察器,但事实并非如此。我错过了什么


谢谢。

您尚未为FrameChanged分配任何事件

yourInstance.FrameChanged+= () => DoSomething();

要调用事件处理程序,需要做两件事

  • 您需要将事件处理程序挂接到事件
  • 你需要启动这个活动
  • 您忽略了显示代码中的第一项。如果尚未将事件处理程序连接到事件,则需要这样做。你可以这样做:

    someObject.FrameChanged += SomeObjectFrameChanged;
    
    ...
    
    private void SomeObjectFrameChanged(object sender, EventArgs e)
    {
        ... code here
    }
    
    set
    {
        if (_currentFrame == value) return;
    
        //#3
        _currentFrame = value;
        OnFrameChanged();
    }
    
    第二个在表面上看起来不错,属性调用OnFrameChanged

    yourInstance.FrameChanged+= () => DoSomething();
    
    顺便说一下,OnFrameChanged不是实现事件处理程序激发方法的推荐方法,您应该使用以下模板:

    protected virtual void OnFrameChanged()
    {
        var evt = FrameChanged;
        if (evt != null) evt(this, EventArgs.Empty);
    }
    
    此更改(将事件值提升为局部变量)的原因是,如果您处于多线程环境中,在检查事件是否至少有一个事件处理程序(
    !=null
    )后,另一个线程可能会取消订阅最后一个事件处理程序。吹毛求疵,但你还是应该改变它

    在C#6中,您可以将上述方法更改为:

    protected virtual void OnFrameChanged()
    {
        FrameChanged?.Invoke(this, EventArgs.Empty);
    }
    
    因为这会做同样的事情


    但现在我们来看看您的代码和期望中的真正缺陷:

    _currentFrame += _currentFrame;
    
    您希望这会触发您的事件,但这是错误的

    您直接访问backing字段,它绕过属性中的所有代码,因此这里没有调用
    OnFrameChanged
    的代码,因此不会触发事件

    相反,您应该访问该属性:


    次要的吹毛求疵#2是您应该确保只有在属性实际发生更改时才触发
    PropertyChanged

    Age = 1;
    Age = 1; // did not change, do not fire PropertyChanged
    
    因此,您应该实现如下属性设置器:

    someObject.FrameChanged += SomeObjectFrameChanged;
    
    ...
    
    private void SomeObjectFrameChanged(object sender, EventArgs e)
    {
        ... code here
    }
    
    set
    {
        if (_currentFrame == value) return;
    
        //#3
        _currentFrame = value;
        OnFrameChanged();
    }
    

    …+=(发送方,e)=>DoSomething()如果事件处理程序直接更改支持字段,则不会触发。谢谢!这是有道理的。为什么它要触发事件处理程序?您不是在更改属性,而是在更改支持字段。没有对备份字段的监控,您只有属性中的代码。因此,请尝试
    Age+=Age
    Age++
    。谢谢!正是我需要的解释。