【问题标题】:C# - Interfaces / Abstract class - ensure event is raised on methodC# - 接口/抽象类 - 确保在方法上引发事件
【发布时间】:2010-07-07 12:19:46
【问题描述】:

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

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

我希望在 Put 成功时引发事件 (作为参考,Put 可以在数据库中存储一行,或者在文件系统上存储文件等...)

因此,为 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 的每个实现都会引发事件的方法 - 我应该有一个抽象类,还是接口?

【问题讨论】:

    标签: c# events interface


    【解决方案1】:

    我的建议:

    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】:

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

    最后,鼓励引发事件的最好方法是编写开发人员应该使用的方法,通过抽象类的方式。这样一来,他们就必须特意使用它

    【讨论】:

      【解决方案3】:

      您需要有抽象类从您的接口实现 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】:

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

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

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

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

        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】:

        如果真的需要使用接口,那么newPostSharp 2可以做切面继承。不幸的是,要获得该功能,您至少需要以 200 美元的价格购买个人许可证。

        有了这样一个方面,你可以把它放在你接口中声明的方法上,你接口的所有实现都会继承它。

        【讨论】:

          【解决方案6】:
           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 as protected 所以所有派生类都必须实现它,但客户端代码不能调用它。

          【讨论】:

            【解决方案7】:

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

            我只想补充一点,如果您希望 IStore&lt;TEntity&gt; 的任何实现总是在调用 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 上提出。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2013-02-26
              • 2011-11-20
              • 1970-01-01
              • 2017-07-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多