Почему я не могу защитить интерфейсные элементы?

Каков аргумент против объявления элементов защищенного доступа на интерфейсах? Это, например, недействительно:

public interface IOrange
{
    public OrangePeel Peel { get; }
    protected OrangePips Seeds { get; }
}

В этом примере интерфейс IOrange гарантирует, что разработчики, по крайней мере, предоставят экземпляр OrangePips своим наследникам. Если бы разработчик захотел, они могли бы расширить область до полного public:

public class NavelOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    protected OrangePips Seeds { get { return null; } }
}

public class ValenciaOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    public OrangePips Seeds { get { return new OrangePips(6); } }
}

Цель членов protected на интерфейсах - предоставить контракт поддержки для наследователей (подклассов), например:

public class SpecialNavelOrange : NavelOrange
{
    ...
    // Having a seed value is useful to me.
    OrangePips seeds = this.Seeds; 
    ...
}

(По общему признанию, это не сработало бы для struct s)

Я не вижу много примеров для модификаторов private или internal в интерфейсах, но поддержка обоих модификаторов public и protected кажется вполне разумной.


Я попытаюсь объяснить полезность членов protected на interface, полностью отделив их от interface:

Представьте себе новое ключевое слово С#, support, чтобы обеспечить выполнение контрактов с наследниками, чтобы мы объявляли следующее:

public support IOrangeSupport
{
    OrangePips Seeds { get; }
}

Это позволит нам заключать контракты с классами для предоставления защищенным членам их наследников:

public class NavelOrange : IOrange, IOrangeSupport
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    protected OrangePips Seeds { get { return null; } }
}

Это не особенно полезно, потому что классы уже подразумевали бы этот контракт, предоставляя в первую очередь членов protected.

Но тогда мы могли бы также сделать это:

public interface IOrange : IOrangeSupport
{
   ...
}

Таким образом, применяя IOrangeSupport ко всем классам, которые реализуют IOrange и требуют от них предоставления определенных членов protected - которые мы не можем сейчас делать.

Ответ 1

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

public interface IOrange
{
    OrangePeel Peel { get; }
}

public abstract class OrangeBase : IOrange
{
    protected OrangeBase() {}
    protected abstract OrangePips Seeds { get; }
    public abstract OrangePeel Peel { get; }
}

public class NavelOrange : OrangeBase
{
    public override OrangePeel Peel { get { return new OrangePeel(); } }
    protected override OrangePips Seeds { get { return null; } }
}

public class ValenciaOrange : OrangeBase
{
    public override OrangePeel Peel { get { return new OrangePeel(); } }
    protected override OrangePips Seeds { get { return new OrangePips(6); } }
}

Изменить: справедливо утверждать, что если у нас есть PlasticOrange, который происходит от класса Ornament, он может реализовать только IOrange, а не метод Seeds protected. Это нормально. Интерфейс по определению - это контракт между вызывающим и объектом, а не между классом и его подклассами. Абстрактный класс так же близок, как мы приходим к этому понятию. И это нормально. То, что вы по существу предлагаете, - это еще одна конструкция на языке, с помощью которой мы можем переключать подклассы из одного базового класса в другой без нарушения сборки. Для меня это не имеет смысла.

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

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

Ответ 2

Не могу понять, почему так хочется. Если вы хотите, чтобы производный класс предоставлял реализацию конкретного метода, перейдите к абстрактным базовым классам. Интерфейсы - это просто интерфейсы. Публичный контракт, больше ничего. Думайте об интерфейсе как о спецификации, которая описывает, как реализация должна выглядеть для внешнего мира. В спецификации для двухконтактного разъема не указано (по крайней мере, я так полагаю), какой должна быть его внутренняя структура. Он просто должен быть совместим по интерфейсу с штепсельной розеткой. Plug
(источник: made-in-china.com)

Ответ 3

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

Ответ 4

Существуют интерфейсы, позволяющие людям получить доступ к вашему классу, не зная, какова конкретная реализация. Он полностью разводит реализацию от договора передачи данных.

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

Ответ 5

Элементы интерфейса являются общедоступным API; такие вещи, как protected и т.д., - это детали реализации, а интерфейсы не имеют никакой реализации. Я подозреваю, что вы ищете явную реализацию интерфейса:

public class NavelOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    OrangePips IOrange.Seeds { get { return null; } }
}

Ответ 6

Интерфейс - это контракт, который promises выполняет определенные функции для клиентов. Другими словами, цель интерфейса состоит в том, чтобы иметь возможность вводить в него тип и передавать его таким образом, чтобы кодировать, который нуждается в функциях, гарантированных этим интерфейсом. Так как клиентский код типа не может получить доступ к защищенным членам этого типа, нет смысла объявлять защищенные элементы в интерфейсе.

Ответ 7

Интерфейс похож на форму ключа.

введите описание изображения здесь

Это не ключ.

Это не блокировка.

Это просто тонкая точка контакта.

По этой причине все члены интерфейса (который определяет форму ключа) должны быть общедоступными.

Для открытия ключа блокировки важно, чтобы оба они имели одну и ту же форму.

Сделав форму (интерфейс) общедоступной, вы можете позволить другим создавать совместимые блокировки или совместимые ключи.

В противном случае, сделав его (интерфейс) внутренним, вы не разрешите другим создавать совместимые блокировки или совместимые ключи.

Ответ 8

Интерфейс - это все, что может сделать определенный объект, поэтому при использовании класса, который реализует этот интерфейс, разработчик ожидает, что все члены будут реализованы, поэтому модификатор защищенного доступа ничего не значит для интерфейсов.

Ответ 9

Интерфейс содержит только публичные элементы. Защищенный означает, что все, что вы объявляете, доступно только для экземпляров класса и производного класса.

Ответ 10

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

Ответ 11

При реализации интерфейса тип утверждает, что он поддерживает определенный набор методов. Если какой-либо из этих методов не был общедоступным, он не будет доступен для вызывающих абонентов, и, таким образом, тип не поддерживает интерфейс, как указано.

Ответ 12

Любой класс, который реализует интерфейс .net, должен включать в себя реализации всех членов интерфейса. Кроме того, любой класс может выставлять производному классу любые его члены. Требование того, что реализация интерфейса должна включать элемент, который будет использоваться только из производных классов, не будет полезной целью, если только (1) такой член не может быть видимым чему-либо вне интерфейса, или (2) реализация интерфейса может использовать членов, которые они сами не определили. Если интерфейсам было разрешено включать вложенные классы (которые могли бы обращаться к членам интерфейса protected), то члены интерфейса protected имели бы смысл. Действительно, они могут быть очень полезными, если класс, вложенный в интерфейс, может определять методы расширения для этого интерфейса. К сожалению, такого средства не существует.

Кстати, даже не имея возможности встраивать классы в интерфейсы, было бы полезно применить модификатор доступа internal к членам интерфейса, при этом только сборка, в которой определяется интерфейс, сможет определить любой для него.

Ответ 13

в отличие от абстрактных базовых классов, защищенные интерфейсы допускают "множественное наследование" (абстрактных классов), что я нашел бы полезным один или два раза...