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

c# interface protected access-modifiers

44889 просмотра

12 ответа

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

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с)

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


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

Давайте представим новое ключевое слово C # 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членов - что мы сейчас не можем сделать.

Автор: ajlane Источник Размещён: 17.05.2019 02:55

Ответы (12)


55 плюса

Решение

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

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. Это хорошо. Интерфейс по определению является контрактом между вызывающей стороной и объектом, а не между классом и его подклассами. Абстрактный класс настолько близок, насколько мы подходим к этой концепции. И это нормально. По сути, вы предлагаете еще одну конструкцию языка, с помощью которой мы можем переключать подклассы из одного базового класса в другой, не нарушая сборку. Для меня это не имеет смысла.

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

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

Автор: Szymon Rozga Размещён: 05.02.2009 03:13

48 плюса

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

Автор: Anton Gogolev Размещён: 05.02.2009 02:43

15 плюса

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

Автор: annakata Размещён: 05.02.2009 02:40

9 плюса

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

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

Автор: JaredPar Размещён: 05.02.2009 02:40

7 плюса

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

public class NavelOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    OrangePips IOrange.Seeds { get { return null; } }
}
Автор: Marc Gravell Размещён: 05.02.2009 02:40

1 плюс

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

Автор: Vojislav Stojkovic Размещён: 05.02.2009 02:48

1 плюс

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

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

Это не ключ.

Это не замок.

Это просто тонкий контактный пункт.

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

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

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

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

Автор: Marco Staffoli Размещён: 01.11.2017 04:25

0 плюса

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

Автор: Gerrie Schenck Размещён: 05.02.2009 02:39

0 плюса

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

Автор: Frederick The Fool Размещён: 05.02.2009 02:45

0 плюса

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

Автор: Brian Rasmussen Размещён: 05.02.2009 02:49

0 плюса

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

Автор: Jason Punyon Размещён: 05.02.2009 02:40

0 плюса

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

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

Автор: supercat Размещён: 12.06.2012 07:03
Вопросы из категории :
32x32