C # частный (скрытый) базовый класс

Можно ли сделать базовый класс C # доступным только в библиотечной сборке, в которую он скомпилирован, а другие подклассы, унаследованные от него, сделать общедоступными?

Например:

using System.IO;

class BaseOutput: Stream           // Hidden base class
{
    protected BaseOutput(Stream o)
    { ... }

    ...lots of common methods...
}

public class MyOutput: BaseOutput  // Public subclass
{
    public BaseOutput(Stream o):
        base(o)
    { ... }

    public override int Write(int b)
    { ... }
}

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

ОБНОВЛЕНИЕ

Мое решение для этой конкретной библиотеки - создать базовый класс public и abstract и задокументировать его с помощью «Не использовать этот базовый класс напрямую». Я также создаю конструктор базового класса internal, который эффективно предотвращает использование или наследование класса внешними клиентами.

(Это позор, потому что другие языки O-O позволяют мне иметь скрытые базовые классы.)


person David R Tribble    schedule 01.06.2012    source источник
comment
почему бы вам не сделать конструктор BaseOutput внутренним, чтобы внешний код не мог наследовать от него?   -  person Mike Zboray    schedule 02.06.2012
comment
@mikez: Да, я так и сделал, см. обновление выше.   -  person David R Tribble    schedule 02.06.2012
comment
открытый класс с внутренним конструктором, возможно, лучший вариант (образец в моем ответе)   -  person Alexei Levenkov    schedule 02.06.2012


Ответы (3)


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

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

person CodesInChaos    schedule 01.06.2012
comment
Очень плохо. Java позволяет мне это делать. - person David R Tribble; 02.06.2012
comment
Потому что иногда это избавило бы меня от некоторого количества шаблонов. Например, при реализации одного и того же интерфейса в нескольких классах. - person CodesInChaos; 02.06.2012
comment
Все дело в том, чтобы поместить как можно больше общих методов и переменных в общий базовый класс, чтобы вам не приходилось записывать каждый из них в каждом подклассе. Это одно из наиболее распространенных применений базовых классов, то есть совместное использование кода реализации вместо ненужного дублирования кода. - person David R Tribble; 02.06.2012

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

person Jeff Watkins    schedule 01.06.2012
comment
Я не хочу создавать много методов пересылки. Вся суть скрытого базового класса заключается в том, чтобы избежать репликации множества (общих) методов. - person David R Tribble; 02.06.2012
comment
действительно, в любом случае следует предпочитать композицию наследованию (en.wikipedia.org/wiki/Composition_over_inheritance) - person jeroenh; 02.06.2012
comment
@jeroenh - Это полная противоположность моей точке зрения. Я хочу, чтобы базовый класс реализовывал большинство методов и переменных, и я хочу, чтобы каждый производный подкласс реализовывал как можно меньше. - person David R Tribble; 09.07.2015

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

internal static class MyStreamExtensions
{
   internal static int UsefulOne(this Stream stream)
   {
     return 42; 
   }
}   

Другой подход - сделать конструктор внутренним, чтобы предотвратить непреднамеренное наследие от этого класса:

public class BaseOutput: Stream
{
    internal BaseOutput(Stream o)
    { ... }

    ...lots of common methods...
}

Это сделает код более понятным по сравнению с «невидимым» промежуточным классом в иерархии.

person Alexei Levenkov    schedule 01.06.2012