代码之家  ›  专栏  ›  技术社区  ›  Alex

C-接口/抽象类-确保在方法上引发事件

  •  7
  • Alex  · 技术社区  · 14 年前

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

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

    我希望通过Put的成功举办一个活动 (作为参考,Put可以在数据库中存储一行,或在文件系统中存储文件等…)

    因此,为产品类型实现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 回复  |  直到 14 年前
        1
  •  9
  •   Andrey    14 年前

    我的建议是:

    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 在你们班

        2
  •  3
  •   Dan McClain    14 年前

    实际上,没有办法确保IStore的每个实现都会引发一个事件。您可以有一个具有Put方法的抽象类,但这并不意味着您可以在抽象类的子类中有一个Put方法,该子类完全忽略抽象类的方法。

    最后,最好的方法 鼓励 事件的引发是通过抽象类来编写开发人员应该使用的方法。那样的话,他们就得走了 使用它

        3
  •  2
  •   Andrew Bezzub    14 年前

    您需要让抽象类从接口实现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();
        }
    }
    
        4
  •  1
  •   Thibault Falise    14 年前

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

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

    也就是说,即使使用抽象类也不会强制其他开发人员使用您的方法,因为它们可能会覆盖您的方法。

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

    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方法引发,该方法是公开可见的。

        5
  •  0
  •   Lasse V. Karlsen    14 年前

    如果你真的需要使用一个接口,那么新的 PostSharp 2 可以做方面继承。不幸的是,要获得这项功能,你至少需要购买200美元的个人许可证。

    有了这样一个方面,您将把它放在接口中声明的方法上,并且接口的所有实现都将继承它。

        6
  •  0
  •   Arseny    14 年前
     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
         }
    
    }
    

    一些注意事项:我确实将其设置为受保护的,因此所有派生类都必须实现它,但客户端代码不能调用它。

        7
  •  0
  •   Dan Tao    14 年前

    编写抽象类以包装 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 将在一个成功的 .