Каков прецедент для (С# 7.2) "частного защищенного" модификатора?
В С# 7.2 представлен частный защищенный модификатор.
Я всегда защищал доступ к полям со свойствами, предоставляя доступ через методы Get/Set, поскольку я обычно не хочу, чтобы внутреннее состояние моего объекта было изменено чем-либо, кроме моего собственного класса.
Я пытаюсь понять, почему команда языка С# добавила эту функцию. После обширного поиска в google и чтения и просмотра "каких новых" носителей (я смотрел пресс-релиз, подробности и видео от Mads Torgerson), я до сих пор не мудрее.
Для меня это, по-видимому, позволяет разработчику нарушить принцип замены Лискова, но это может быть из-за того, что я не понимаю, почему эта функция существует.
Я понимаю, как это можно использовать, а не почему - пожалуйста, кто-то может предоставить пример использования в реальном мире, а не надуманный в документах MSDN?
Ответы
Ответ 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();
}
Теперь он скомпилируется, и вам не нужно подвергать свои внутренние функции.