Предположим, у меня есть следующие классы в библиотеке
public abstract class HiddenBaseClass
{
//stuff
}
public abstract class ClassA : HiddenBaseClass
{
//stuff
}
public abstract class ClassB : HiddenBaseClass
{
//stuff
}
Я хочу предотвратить наследование HiddenBaseClass
за пределами библиотеки, но я хочу, чтобы ClassA
и ClassB
наследовались.
Я не могу сделать HiddenBaseClass
internal class
, потому что это означало бы, что HiddenBaseClass
менее доступен, чем ClassA
и ClassB
.
Есть ли способ обойти это?
Если вы можете наследовать от ClassA
, то вы также наследуете от HiddenBaseClass
, поэтому ваши требования конфликтуют. Какие проблемы вызывает наследование от HiddenBaseClass
, которых вы хотите избежать?
Потому что я не хочу копировать и вставлять код между ClassA
и ClassB
, но у меня также нет причин проектировать HiddenBaseClass
таким образом, чтобы поддерживать наследование пользователем.
Хотя такой код можно спроектировать, согласно моему ответу, я бы предложил использовать композицию, а не наследование, где это возможно. Мы не можем точно сказать, поможет ли это здесь, но это следует учитывать.
Вопреки комментариям к вопросу, я считаю, что этот сценарий может иметь смысл, если HiddenBaseClass
имеет аспекты, которые вам нужно полагаться на внутреннюю реализацию (потому что вы доверяете внутренним реализациям), но предоставляете другие абстрактные операции для реализации внешнего кода. Это может быть неподходящим дизайном для вашего варианта использования, но это не является необоснованным.
Один простой способ сделать невозможным наследование от него непосредственно за пределами той же библиотеки — дать ему внутренний конструктор:
public abstract class HiddenBaseClass
{
// Only classes in the same assembly can chain to this constructor.
internal HiddenBaseClass() {}
}
Пока все конструкторы в классе являются внутренними (или закрытыми, защищенными или частными), это не позволит классам в других сборках связывать свои конструкторы в цепочку с конструкторами базового класса, тем самым предотвращая наследование.
Он также может определить интерфейс и пометить его как внутренний. В этом случае он может оставить абстрактный класс общедоступным.
@Transcendent: это не поможет при повторном использовании кода. Мой ответ по-прежнему сохраняет абстрактный класс общедоступным - это только внутренний конструктор.
Конечно, сэр Джон Скит! :) Я всего лишь пытался предложить альтернативный способ. Я не думаю, что есть кто-то, кто посмеет доказать, что вы (Чак Норрис в программировании) не правы.
Как вежливо указывалось в комментариях, это не лучшая структура для такого сценария. В конце концов, я иду к такой реализации:
internal sealed class HiddenBaseClass
{
//stuff
}
public abstract class ClassA
{
internal HiddenBaseClass { get; set; }
//stuff that uses HiddenBaseClass
}
public abstract class ClassB
{
internal HiddenBaseClass { get; set; }
//more stuff
}
Прошу прощения, что снова задаю неправильные вопросы.
запечатанные классы не могут быть унаследованы!
Я не наследую запечатанный класс, не так ли? Редактировать: о, неважно, это была оплошность, я отредактировал это.
Ваш код не компилируется, вы пытались его протестировать перед публикацией ответа?
Я случайно унаследовал класс, когда не хотел этого. Я отредактировал ответ.
Да, я это заметил. То, что вы делаете, на самом деле называется инверсией управления.
Сохраняйте код, как в вопросе, который вы разместили, просто добавьте это internal HiddenBaseClass() {}
(как ответ Джона Скита)
Сценарий очень бессмысленный!