在接口中具有事件是否是错误的做法? C#

时间:2018-09-05 01:45:35

标签: c# interface delegates

我试图更多地使用界面,并且经常发现自己将事件放入界面中。感觉很奇怪,因为我让实现者知道何时在其实现中引发这些事件。

例如,我有一个ILevellable接口,该接口仅声明对象应具有xp,一个级别和一个最大级别,以及一些修改这些值的方法。引用ILevellable的类可能想知道何时升级,因此我为OnLevelUp添加了一个Action ...,但是该实现可能未将其放在正确的位置。

public interface ILevellable
{
    int Level { get; }
    int MaxLevel { get; }
    int XP { get; }
    event Action<bool> OnXPChanged;
    event Action<ILevellable> OnLevelUp;
    event Action OnMaxLevelReached;

    void LevelUp(int newLevel);
}

我应该相信实现此接口的用户会知道在哪里实现吗?我会假设不是。尤其是因为某些事件可能带有参数,用户又可能不知道它应该代表什么。

我感谢任何指导!我是这种工作的新手。

谢谢!

2 个答案:

答案 0 :(得分:1)

可以在界面中定义事件。但是,将“发件人”和“事件参数”都传递到事件中符合惯例。 TypedEventHandler是一种简单的方法。例如:

using Windows.Foundation;

public struct LevellableChange {
    public LevellableChange( int dl, int dxp) 
    { 
         this.ChangeInLevel = dl;
         this.ChangeInXP = dxp;
    }
    int ChangeInLevel { get; }
    int ChangeInXP {get;}
}

public interface ILevellable
{
    int Level { get; }
    int MaxLevel { get; }
    int XP { get; }
    event TypedEventHandler< ILevellable, LevellableChange> Changed;
}

然后,实现它们的标准方法如下:

public class Levellable: ILevellable
{
    public event TypedEventHandler<ILevellable, LevellableChange> Changed;

    public int Level {
        get {
            return this._level;
        }
        private set {
            if (value != this._level) {
                int oldLevel = this._level;
                this._level = value;
                this.Changed?.Invoke(this, new LevellableChange(value - oldLevel, 0));
            }
        }
    }
    private int _level;

    // similar for XP. 
}

另一个评论是,有一个实现INotifyPropertyChanged的类,然后养成从其派生的习惯很有用。加上Visual Studio中的代码片段,这使事情变得容易得多。确实,对于上面的示例,INotifyPropertyChanged不够,因为它没有将更改赋予先前的值。

答案 1 :(得分:0)

首先,您的接口定义中没有委托类型,但事件。查看乔恩·斯凯特(Jon Skeet)的this answer,以了解委托和事件之间的区别。说完接口中有事件是完全可以的,即使.Net也可以这样做,再考虑一下著名的INotifyPropertyChanged接口。它只是定义了一个事件...

第二:

  

我应该相信实现此接口的用户会知道在哪里实现吗?

定义接口时,您实际上并不关心实现者,而不是消费者,因此,对于看到您的合同定义的消费者来说,知道他/她可以订阅名为{{1 }}。假设我确实在使用您的界面,我不知道您触发OnLevelUp事件的方式或时间,我也不在乎,因为您为该事件指定了一个非常语义化和有意义的名称,因此我可以非常确定在增加OnLevelUp的Level属性时会触发该事件。