Лучший способ выставить защищенные поля - PullRequest
3 голосов
/ 22 апреля 2009

У меня есть такой базовый класс:

 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, он жалуется на то, что не объявляет видимые поля экземпляра, и рекомендует изменить его на частное и выставить его как защищенное свойство.

Есть мысли? Я думаю, что это сообщение можно игнорировать.

Ответы [ 6 ]

12 голосов
/ 22 апреля 2009

Для любого класса существует два вида использования клиентским кодом: код, который ссылается на ваш класс, и код, который наследует ваш класс. Широко признано, что второй вид использования, безусловно, наиболее тесно связан. Изменения в вашем классе напрямую влияют на их внутреннюю механику. Такое предоставление защищенных членов, как это, означает, что изменения в вашем базовом классе будут влиять на работу ваших производных классов непредсказуемым образом без сравнения кода каждого базового и производного класса. В равной степени плохо, ваши производные классы могут изменять внутренние компоненты базового класса.

Если вы действительно хотите выставлять внутренние элементы данных, как это, оберните частные элементы данных в защищенные свойства (как предлагает gisresearch). Эти свойства (вместе с любыми защищенными методами) составляют интерфейс наследования вашего класса. Как и любой интерфейс, предоставляемый внешним клиентам (будь то просто путем определения общедоступных методов и свойств или явной реализации интерфейса), этим интерфейсом вам нужно будет управлять, особенно в больших кодовых базах. Интерфейс может быть изменен, но должен быть изменен как осознанное решение.

Если вы работаете с защищенными членами данных напрямую, вы гораздо меньше контролируете зависимости между базовым и производным классами. Поверьте мне: даже неспособность определить, какие последствия могут иметь изменения, может быть очень неприятной вещью.

5 голосов
/ 22 апреля 2009

Как рекомендуется, поля вашего класса должны быть помечены как частные и завернутый в свойство getter / setter

так вместо

protected object m_commandArgument;

использовать

private object m_commandArgument;

protected object CommandArgument {get; set;}

В этом есть несколько преимуществ, но простым использованием будет обработка / проверка исключений в вашем установщике.

, например

private string _email;
protected string Email
{ 
   get { return _email; }
   set 
   {
       if(value.IndexOf("@") > 0)
           _email = value;
       else
            throw new ArgumentException("Not a valid Email");
   }
}
4 голосов
/ 22 апреля 2009

Совет FxCop - это звук. Вы не хотите подвергать защищенные поля производным классам direclty. Состояние, управляемое базовым классом, должно управляться базовым классом - никогда не изменяться напрямую каким-либо производным классом.

1 голос
/ 22 апреля 2009

Используйте свойства. Измените переменные-члены на private и затем настройте защищенные свойства для каждой переменной-члена.

С уважением,
Frank

0 голосов
/ 22 апреля 2009

Пол Александр прав, как и FxCop.

Вы хотите сделать свои поля приватными и предоставить их через свойство, чтобы предотвратить изменение переменной производными классами самостоятельно. Принуждение их пройти через свойство дает базовому классу возможность проверить и / или отклонить любые изменения.

0 голосов
/ 22 апреля 2009

Как правило, FxCop рекомендует делать

private object m_commandArgument;

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

Это основано на правиле инкапсуляции OO (одно из трех правил OO). Возможно, вы захотите проверить значение перед присваиванием , и вы хотите убедиться, что оно не напрямую обрабатывается производным классом.

...