C# - Interfaces / Abstract class - 确保在方法上引发事件

时间:2010-07-07 12:19:46

标签: c# events interface

我有一个定义为IStore的接口,有两种方法:

public interface IStore<TEntity>
{
    TEntity Get(object identifier);
    void Put(TEntity entity);
}

我想要在Put的成功上提出一个事件 (作为参考,Put可以在db中存储一行,或者在文件系统上存储文件等...)

因此,为Product类型实现Istore的类看起来有点像这样:

class MyStore : IStore<Product>
{
    public Product Get(object identifier)
    {
        //whatever
    }

    public void Put(Product entity)
    {
        //Store the product in db
        //RAISE EVENT ON SUCCESS
    }
}

我所追求的是一种确保IStore的每次实施都能引发事件的方法 - 我应该有一个抽象类,或者是接口吗?

7 个答案:

答案 0 :(得分:9)

我的建议:

public abstract class Store<TEntity>
{
    public abstract TEntity Get(object identifier);
    public void Put(TEntity entity)
    {
        //Do actions before call
        InternalPut(entity);
        //Raise event or other postprocessing
    }

    protected abstract void InternalPut(TEntity entity);
}

然后在您的班级中覆盖InternalPut

答案 1 :(得分:3)

确实无法确保IStore的每个实现都会引发事件。你可以有一个带有put方法的抽象类,但这并不意味着你可以在抽象类的子类中有一个完全忽略抽象类方法的put方法。

最后,鼓励引发事件的最佳方法是编写开发人员应该使用的方法,通过抽象类。这样,他们就不得不而不是来使用它

答案 2 :(得分:2)

您需要从您的界面中实现Put方法的抽象类。您还可以添加像PutImpl这样的抽象方法,如下所示:

public abstract class MyStoreBase : IStore<TEntity>
{
    public abstract TEntity Get(object identifier);

    public abstract void PutImpl(TEntity entity);

    public void Put(TEntity entity)
    {
        // Each inheritor will implement this method.
        PutImpl(entity);

        // But event is fired in base class.
        FireEvent();
    }
}

答案 3 :(得分:1)

是的,你应该使用抽象类而不是接口。

如果您决定使用实现您的接口的抽象类,它将不会阻止其他开发人员实现他们自己的接口版本,这最终不会引发该事件。

话虽这么说,即使使用抽象类也不会强迫其他开发人员使用你的方法,因为他们可能会覆盖它。

我认为最好的方法是使用模板方法:

public abstract class AbstractStore<TEntity>
{
    public TEntity Get(object identifier);
    public sealed void Put(TEntity entity)
    {
        if (DoPut(entity))
        {
            // raise event
        }
    }

    protected abstract bool DoPut(TEntity entity);
}

真正的商店必须实现DoPut方法,返回一个布尔值,指示Put操作是否成功。该事件将从Put方法中提出,该方法是公开可见的。

答案 4 :(得分:0)

如果您确实需要使用接口,那么新的PostSharp 2可以执行方面继承。不幸的是,要获得该功能,您需要至少购买200美元的个人许可证。

通过这样的方面,您可以将它放在接口中声明的方法上,并且接口的所有实现都将继承它。

答案 5 :(得分:0)

 abstract class Store<TEntity>
{
     public abstract TEntity Get(object identifier);
     protected abstract void Put(TEntity entity);
     public void PutBase(TEntity entity)
     {
         Put(entity);
         //Raise event here
     }

}

注意:我确实将Put作为受保护的,因此所有派生类都必须实现它,但客户端代码无法调用它。

答案 6 :(得分:0)

正如其他人已经建议的那样,编写一个抽象类来包装一个类似PutInner的方法绝对是解决这个问题的最好方法。

我想补充一点,如果你想要IStore<TEntity>的任何实现总是在调用Put时引发一个事件,我建议你也将所述事件添加到界面本身:

public interface IStore<TEntity>
{
    event EventHandler<EntityEventArgs<TEntity>> EntityAdded;

    TEntity Get(object identifier);
    void Put(TEntity entity);
}

public EntityEventArgs<TEntity> : EventArgs
{
    public TEntity Entity { get; set; }
}

这不是强制实现者做任何事情;但它确实明确表示期望EntityAdded会成功Put