【问题标题】:Best way to expose protected fields公开受保护字段的最佳方式
【发布时间】:2009-04-22 19:24:08
【问题描述】:

我有一个这样的基类:

 public class BaseModalCommand
 {

    protected object m_commandArgument;
    protected int m_commandID;
    protected int m_enableUIFlags;

    public virtual void OnIdle()
    {
    }

    public virtual void OnResume()
    {
    }

    public virtual void OnStart(int commandID, object argument)
    {
    }

    public virtual void OnStop()
    {
    }



    public virtual int EnableUIFlags
    {
        get
        {
            return this.m_enableUIFlags;
        }
    }
}

虚拟方法将在派生类型中被覆盖。如果我通过 FxCop 运行它,它会抱怨没有声明可见的实例字段,并建议将其更改为私有并将其公开为受保护的属性。

有什么想法吗?我认为可以忽略此消息。

【问题讨论】:

    标签: c# properties field


    【解决方案1】:

    对于任何类,客户端代码都有两种用途:引用您的类的代码和继承您的类的代码。人们普遍认为,第二种使用是迄今为止最紧密耦合的。你班级的变化直接影响他们的内部机制。像这样暴露受保护的成员意味着基类中的更改将影响派生类的工作方式,如果不比较每个基类和派生类的代码,则无法预测。同样糟糕的是,您的派生类可以修改基类的内部结构。

    如果您真的想像这样公开内部数据成员,请将私有数据成员包装在受保护的属性中(如 gisresearch 建议的那样)。这些属性(连同任何受保护的方法)构成您的类的继承接口。与暴露给外部客户端的任何接口一样(无论是通过定义公共方法和属性,还是通过显式接口实现),这个接口是您需要管理的,尤其是在较大的代码库中。界面可以更改,但应作为有意识的决定进行更改。

    如果您直接使用受保护的数据成员,您对基类和派生类之间的依赖关系的控制就会少得多。相信我:甚至无法确定更改可能产生的影响可能是一件非常不愉快的事情。

    【讨论】:

      【解决方案2】:

      作为最佳实践,您的课程字段应标记为私有 并包裹在 getter/setter 属性中

      所以而不是

      protected object m_commandArgument;
      

      使用

      private object m_commandArgument;
      
      protected object CommandArgument {get; set;}
      

      这样做有几个优点,但一个简单的用法是在您的 setter 中进行异常处理/验证。

      例如

      private string _email;
      protected string Email
      { 
         get { return _email; }
         set 
         {
             if(value.IndexOf("@") > 0)
                 _email = value;
             else
                  throw new ArgumentException("Not a valid Email");
         }
      }
      

      【讨论】:

        【解决方案3】:

        FxCop 的建议是合理的。您不想将受保护的字段直接暴露给派生类。基类管理的状态应该由基类管理 - 永远不要被任何派生类直接修改。

        【讨论】:

          【解决方案4】:

          使用属性。将成员变量更改为私有,然后为每个成员变量设置受保护的属性。

          问候,
          弗兰克

          【讨论】:

            【解决方案5】:

            Paul Alexander 是正确的,FxCop 也是如此。

            您希望将字段设为私有并通过属性公开它们,以防止派生类自行更改变量。强制它们通过属性使基类有机会验证和/或拒绝任何修改。

            【讨论】:

              【解决方案6】:

              基本上,FxCop 建议您应该这样做

              private object m_commandArgument;
              
              protected object CommandArgument
              {
                 get { return m_commandArgument; }
                 set { m_commandArgument =value}
              }
              

              这是基于 OO 封装规则(三个 OO 规则之一)。您可能希望在分配之前检查值,并确保派生类不会直接对其进行操作。

              【讨论】:

              • get 需要绕过 return get { return m_commandArgument }
              • 另外,受保护的 CommandArgument 应该是受保护的对象 CommandArgument。
              • 谢谢,根据建议修改。
              猜你喜欢
              • 2021-12-03
              • 2011-01-17
              • 2018-01-05
              • 2021-01-09
              • 2012-05-31
              • 1970-01-01
              • 2011-07-21
              • 2016-12-26
              • 2012-10-13
              相关资源
              最近更新 更多