Подтвердить что ты не робот

Защищенное поле readonly vs protected

У меня есть абстрактный класс, и я бы хотел инициализировать поле readonly в его защищенном конструкторе. Я бы хотел, чтобы это поле readonly доступно в производных классах.

Следуя моей привычке делать все поля частными и подвергая свойствам, я реализовал это следующим образом:

abstract class Foo
{
    private readonly int _field;

    protected Foo(int field)
    {
        _field = field;
    }

    protected int Field
    {
        get { return _field; }
    }
}

Но потом я подумал, есть ли на самом деле много преимуществ в том, чтобы держать поле частным здесь. Я знаю о преимуществах свойств, и в этом вопросе есть несколько вопросов SO, но они сосредоточены на публичных полях, а не на защищенных.

Итак, следует ли перейти к реализации ниже или нет?. Каковы соображения и преимущества/недостатки, которые нужно знать в любом случае?

abstract class Foo
{
    protected readonly int _field;

    protected Foo(int field)
    {
        _field = field;
    }
}
4b9b3361

Ответ 1

Производные классы по-прежнему являются "пользователями" исходного кода; поля также должны быть инкапсулированы из них.

Вы должны думать о базовых классах как безопасных и расширяемых API, а не о классах, которые раскрывают их внутренности. Сохраняйте поля частными - помимо всего прочего, он позволяет базовому классу изменять способ создания этого значения свойства:)

Ответ 2

Я оставлю реализацию или перейду с помощью:

protected Field {get; private set;}

(не совсем то же самое, что поле не является readonly для родительского класса)

Преимущество свойств над полями - это более надежное будущее. Вы можете изменить реализацию родительского класса, не затрагивая детей. Без свойства, которое вы поручили этому полю, всегда быть только для чтения. Использование полей не одобряется по другой причине, они уязвляют непрозрачность: класс описывает точную реализацию поля.

Итак, да, оставьте инкапсуляцию.

Единственное место, где я бы рассматривал использование полей непосредственно для удобочитаемости, - это высоко связанные классы, такие как состояния в шаблоне состояния, но в этом случае сами классы были бы частными.

Ответ 3

Свойства Readonly были реализованы в С# 6.0. Это так же просто, как:

protected Foo(int field)
{
    Field = field;
}

protected int Field { get; }

Ответ 4

abstract class Foo
{
    protected readonly int _field;

    protected Foo(int field)
    {
        _field = field;
    }
}

Будет уместно, так как вы хотите, чтобы производный класс знал об этом. Классы, не относящиеся к типу Foo, не будут иметь доступа к _field.

Ответ 5

Используя отражение, вы можете легко переписать поле readonly. Использование свойства делает его сложнее, потому что поле скрыто (вы все еще можете это сделать). Поэтому я бы предпочел свойство, которое в любом случае является более чистым, потому что вы можете изменить получателя без каких-либо проблем.

Если вы думаете о производительности: свойства вставляются в большинстве случаев.

Переопределить readonly

class Program
{
    static void Main(string[] args)
    {
        Test t = new Test();
        t.OverrideReadonly("TestField", 5);
        t.OverrideReadonly("TestField2", 6);
        t.OverrideReadonly("TestField3", new Test());
    }
}

class Test
{
    protected readonly Int32 TestField = 1;
    protected readonly Int32 TestField2 = 2;
    protected readonly Test TestField3 = null;

    public void OverrideReadonly(String fieldName, Object value)
    {
        FieldInfo field = typeof(Test).GetField(fieldName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        field.SetValue(this, value);
    }
}

Ответ 6

Использование частного поля и защищенного геттера имеет небольшое преимущество: вы не вызываете дополнительный уровень косвенности.

Не забывайте сокращенный способ С# для объявления свойств:

protected int Field { protected get; private set; }