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

Существует ли у С# понятие частного и защищенного наследования?

Есть ли у С# понятие частного/защищенного наследования, а если нет, то почему?

С++


class Foo : private Bar {
 public:
   ...
 }; 

С#


public abstract NServlet class : private System.Web.UI.Page
{
    // error "type expected"
}

Я реализую концепцию "сервлет как" на странице .aspx, и я не хочу, чтобы конкретный класс имел возможность видеть внутренности базы System.Web.UI.Page.

4b9b3361

Ответ 1

С# допускает только наследование. С++ допускал все три вида. Наше государственное наследование подразумевало отношение типа "IS-A", а частное наследование подразумевало отношения "Is-Implemented-In-Terms-Of". Поскольку расслоение (или композиция) выполнило это, возможно, более простое, частное наследование использовалось только тогда, когда это было абсолютно необходимо защищаемым членам или требуемым виртуальным функциям - согласно Скотту Мейерсу в "Эффективном С++", п. 42.

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

Ответ 2

Нет, нет. В чем преимущество этого ограничения?

Частное и защищенное наследование полезно для инкапсуляции (скрытие информации). Защищенное * наследование поддерживается в С++, хотя оно не находится на Java. Вот пример из моего проекта, где это было бы полезно.

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

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

Тем не менее, я думаю, что в С++ (который, опять же, поддерживает частное и защищенное наследование), можно отбросить дочерний класс до родителя и получить доступ к родительским открытым членам. (См. Также Сообщение Криса Карчера). Тем не менее защищенное наследование улучшает скрытие информации. Если члены класса B1 должны быть действительно скрыты в других классах C1 и C2, его можно организовать, создав защищенную переменную класса B1 внутри C1 и C2. Защищенный экземпляр B1 будет доступен для детей C1 и C2. Конечно, этот подход сам по себе не обеспечивает полиморфизма между C1 и C2. Но полиморфизм может быть добавлен (если требуется) путем наследования C1 и C2 из общего интерфейса I1.

*** Для краткости будет использоваться "защищенный", а не "закрытый и защищенный".

** National Instruments Measurement Studio в моем случае.

  • Ник

Ответ 3

Вы можете скрыть наследуемые API от того, чтобы быть общедоступным, объявив того же члена в вашем классе как private и используя новое ключевое слово. См. Скрытие через наследование из MSDN.

Ответ 4

@bdukes: Имейте в виду, что вы действительно не скрываете участника. Например:

class Base
{
   public void F() {}
}
class Derived : Base
{
   new private void F() {}
}

Base o = new Derived();
o.F();  // works

Но это происходит так же, как частное наследование в C++, чего и хотел спрашивающий.

Ответ 5

Если вы хотите, чтобы класс NServlet ничего не знал о странице, вам следует изучить шаблон адаптера. Напишите страницу, на которой будет размещен экземпляр класса NServlet. В зависимости от того, что именно вы делаете, вы могли бы написать широкий массив классов, которые знают только о базовом классе NServlet, не загрязняя ваш API членами страницы asp.net.

Ответ 6

Нет, только публичное наследование.

Ответ 7

Вероятно, вам нужен класс ServletContainer, который подключается к реализации NServlet. В моей книге, не позволяя частному/защищенному наследованию, на самом деле не очень важно, и держит язык менее запутанным - с LINQ и т.д. У нас уже есть достаточно материала для запоминания.

Ответ 8

Я знаю, что это старый вопрос, но я несколько раз сталкивался с этой проблемой при написании С#, и я хочу знать... почему бы просто не использовать интерфейс?

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

Это похоже на С# -принятый способ делать такие вещи.

В первый раз я это сделал, когда понял, что стандартная библиотека С# не имеет доступного для чтения варианта словаря. Я хотел предоставить доступ к словарю, но не хотел давать клиенту возможность изменять элементы в словаре. Таким образом, я определил "класс DictionaryEx < K, V, IV > : Dictionary < K, V > , IReadOnlyDictionary < K, IV > , где V: IV", где K - тип ключа, V - тип действительного значения, а IV - интерфейс к типу V, который предотвращает изменения. Реализация DictionaryEx была в основном простой; единственной трудной частью было создание класса ReadOnlyEnumerator, но даже это не занимало очень много времени.

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

Ответ 9

Первое решение:

защищенный внутренний действует как открытый в той же сборке и защищен на других сборках.

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

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

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


Проблема:

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


Окончательное решение:

Я вернулся к интерфейсу > , чтобы скрыть методы.

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

Чтобы сила использовалась только с интерфейсом, просто сделать защищенные конструкторы и добавить статический метод для построения (я назвал его New). Этот статический новый метод фактически является функцией factory, а возвращает интерфейс. Таким образом, остальная часть кода должна использовать только интерфейс!

Ответ 10

Нет, нет. В чем преимущество этого ограничения?