.NET - 我应该直接调用事件吗?

时间:2018-05-07 07:15:32

标签: c# .net

我现在很长时间陷入模式,最近我意识到我忘了为什么习惯这样做了。

public event EventHandler<string> SomethingChanged;
private void OnSomethingChanged(string something) => SomethingChanged?.Invoke(this, something);

所以,当我想调用这个事件时,我会调用OnSomethingChanged(this, something);。为什么不直接做SomethingChanged?.Invoke(this, state);

感觉非常简单。当C#语法更复杂时,这个OnSomethingChanged模式是否有可能成为一个目的,但今天它几乎没有必要?

事实上,由于这种模式很长,我总是复制粘贴它并替换相关部分。具有讽刺意味的是,我可以回想起几次这样的复制粘贴导致调试我的软件只是为了发现我在这里犯了一个错误,因为匆忙。这也使得直接调用SomethingChanged更好。

1 个答案:

答案 0 :(得分:2)

考虑以下示例:

public class BaseClass 
{
    private int id;
    public int Id 
    { 
        get { return id; }
        set { id = value; SomethingChanged(this, "id"); }
    }

    public event EventHandler<string> SomethingChanged;
}

public class DerivedClass : BaseClass
{
    private string name;
    public string Name 
    { 
        get { return name; }
        set 
        { 
            name = value; 
            //// cannot be invoked directly here
            // SomethingChanged(this, "name"); 
        }
    }
}

c#documentsations mentions this case specifically

  

事件是一种特殊类型的委托,只能在声明它们的类中调用。派生类不能直接调用在基类中声明的事件。虽然有时您可能想要一个只能由基类引发的事件,但大多数情况下,您应该启用派生类来调用基类事件。为此,您可以在包装事件的基类中创建受保护的调用方法。通过调用或重写此调用方法,派生类可以间接调用该事件。

基类中的

私有方法对于triggeres事件没什么帮助,它应该是protected。使方法virtual允许派生类在通知事件订阅者之前/之后添加一些功能也是明智的:

public class BaseClass 
{
    private int id;
    public int Id 
    { 
        get { return id; }
        set { id = value; OnSomethingChanged( "id"); }
    }

    public event EventHandler<string> SomethingChanged;

    protected virtual void OnSomethingChanged(string something)
    {
        SomethingChanged(this, something);
    }
}

public class DerivedClass : BaseClass
{
    private string name;
    public string Name 
    { 
        get { return name; }
        set 
        { 
            name = value; 
            OnSomethingChanged("name"); 
        }
    }

    protected override void OnSomethingChanged(string something)
    {
        base.OnSomethingChanged(something + " (event triggered from derived class)");
    }
}
public static void Main(string[] args)
{
    var item = new DerivedClass();
    item.SomethingChanged += (e,s) => Console.WriteLine(s);
    item.Id = 5;
    item.Name = "abc";
}

此修改示例打印:

id (event triggered from derived class)
name (event triggered from derived class)