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

Каков прецедент для (С# 7.2) "частного защищенного" модификатора?

В С# 7.2 представлен частный защищенный модификатор.

Я всегда защищал доступ к полям со свойствами, предоставляя доступ через методы Get/Set, поскольку я обычно не хочу, чтобы внутреннее состояние моего объекта было изменено чем-либо, кроме моего собственного класса.

Я пытаюсь понять, почему команда языка С# добавила эту функцию. После обширного поиска в google и чтения и просмотра "каких новых" носителей (я смотрел пресс-релиз, подробности и видео от Mads Torgerson), я до сих пор не мудрее.

Для меня это, по-видимому, позволяет разработчику нарушить принцип замены Лискова, но это может быть из-за того, что я не понимаю, почему эта функция существует.

Я понимаю, как это можно использовать, а не почему - пожалуйста, кто-то может предоставить пример использования в реальном мире, а не надуманный в документах MSDN?

4b9b3361

Ответ 1

До С# 7.2 у нас был модификатор protected internal. Это действительно означает, что защищенный OR внутренний, то есть член A доступен для дочерних классов, а также для любого класса в текущей сборке, даже если этот класс не является дочерним по классу A (поэтому ограничение, подразумеваемое "protected", расслаблены).

private protected действительно означает protected AND internal. То есть - член доступен только для дочерних классов, которые находятся в одной и той же сборке, но не для дочерних классов, которые находятся вне сборки (поэтому ограничение, подразумеваемое "защищенным", сужается, становится еще более ограничивающим). Это полезно, если вы строите иерархию классов в своей сборке и не хотите, чтобы дочерние классы из других сборок обращались к определенным частям этой иерархии.

Мы можем взять пример, что Jon Skeet предоставил в комментариях. Предположим, у вас есть класс

public class MyClass {

}

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

Наследование только внутри текущей сборки может быть достигнуто с помощью внутреннего конструктора

public class MyClass {
    internal MyClass() {
    }
}

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

public class MyClass {
    protected MyClass() {
    }
}

И для получения обоих - нужен конструктор private protected:

public class MyClass {
    private protected MyClass() {
    }
}

Ответ 2

Предположим, что у вас есть внутренний класс с именем SomeHelper, который вы хотите использовать как часть реализации публичного абстрактного базового класса:

public abstract class Test
{
    // Won't compile because SomeHelper is internal.
    protected SomeHelper CreateHelper()
    {
        return new SomeHelper();
    }

    public int Func(int x)
    {
        var helper = CreateHelper();
        return helper.DoSomething(x);
    }
}

internal class SomeHelper
{
    public virtual int DoSomething(int x)
    {
        return -x;
    }
}

Это не будет компилироваться, потому что у вас не может быть защищенного метода, возвращающего внутренний тип. Ваш единственный регресс - не использовать SomeHelper таким образом или сделать SomeHelper общедоступным.

(Вы можете сделать SomeHelper защищенным внутренним классом Test, но это не сработает, если SomeHelper предназначено для использования другими классами, которые не производятся из базового класса.)

С введением функции private protected вы можете объявить CreateHelper() следующим образом:

private protected SomeHelper CreateHelper()
{
    return new SomeHelper();
}

Теперь он скомпилируется, и вам не нужно подвергать свои внутренние функции.