Как скрыть (удалить) методы базового класса в С#?
Суть проблемы в том, что для такой иерархии классов:
class A
{
protected void MethodToExpose()
{}
protected void MethodToHide(object param)
{}
}
class B : A
{
new private void MethodToHide(object param)
{}
protected void NewMethodInB()
{}
}
class C : B
{
public void DoSomething()
{
base.MethodToHide("the parameter"); // This still calls A.MethodToHide()
base.MethodToExpose(); // This calls A.MethodToExpose(), but that ok
base.NewMethodInB();
}
}
Как я могу запретить какие-либо классы, которые наследуют от класса "В", вид метода A.MethodToHide()
? В С++ это было достаточно легко, используя объявление типа class B : private A
, но этот синтаксис недействителен в С#.
Для тех, кого это интересует (или интересно, что я действительно пытаюсь сделать), мы пытаемся создать оболочку для Rhino.Commons.NHRepository, которая скрывает методы, которые мы не хотим раскрывать нашим группа разработчиков, поэтому у нас есть способ разработки файлов cookie для разработки нашего приложения, к которому легко могут следовать новые разработчики. Так что да, я считаю, что тест "Is-A" действителен для всей цепочки (WidgetRepository Is-A BaseRepository Is-NHRepository).
Изменить. Я должен был упомянуть, ради аргумента, что класс A является классом API за пределами нашего контроля. В противном случае проблема становится значительно проще.
Ответы
Ответ 1
Вы не можете сделать это и сохранить иерархию. Если возможно, вы должны создать интерфейсы, которые определяют ваш идеал, а затем подклассы базовых классов и реализовать интерфейсы. ссылайтесь только на интерфейсы (а не на типы базового класса).
Шаблон адаптера был создан специально для решения проблемы использования фреймворка, когда его API не соответствует точно вашим потребностям.
Ответ 2
Устаревшее
В классе B переопределить MethodToHide и добавить атрибут Obsolete
[Obsolete("Reason", true)] // true will cause a compile-time error
Set EditorBrowsable
(Как упоминалось ранее)
В классе B переопределить MethodToHide и добавить атрибут EditorBrowsable
[System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]
Исключить исключение
(Как упоминалось ранее)
В классе B переопределить MethodToHide и исключить исключение.
Создать Wrapper
Я думаю, что Майкл Медоус прав. Используйте шаблон адаптера. Этот шаблон также позволяет легче высмеивать код при модульном тестировании.
class B: IInterface
{
protected void MethodToExpose()
{
A a = new A();
a.MethodToExpose();
}
protected void NewMethodInB()
{
}
}
Ответ 3
Если вы хотите настроить набор функций, я бы сказал, что вы хотите сделать оболочку, а не наследовать функциональность. Я не знаю, как сделать то, что вы хотите на С#.
Подумайте об этом, что если какой-то код вне вашего контроля хочет этот экземпляр NHRepository
для чего-то... но вы удалили функциональность из функции, которая ему нужна в вашем дочернем классе (который вы отправляли, так как ваш единственный экземпляр NHRepository
.) Все идет бум. Вот почему я не думаю, что это возможно даже без уродливого взлома.
Ответ 4
Если вы используете Visual Studio, вы можете скрывать методы/свойства от intelliprompt с помощью этого атрибута:
class A
{
protected void MethodToExpose()
{}
[System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]
protected void MethodToHide(object param)
{}
}
На самом деле он не избавится от функции, но если они только ваши внутренние люди. Это может быть достаточно близко.
Ответ 5
На мой взгляд, лучший способ сделать это, если вы просто хотите скрыть и не переопределить и экстернализировать новую функциональность, - это просто добавить атрибут EditorBrowsableState.
Он скрывает метод в редакторе визуальной студии. Кто когда-либо попытается использовать его, в конечном итоге будет ошибка времени компиляции.
Просто добавьте этот код поверх своего метода:
[System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]
Например
public class User
{
public void DoSomething()
{
Something...
}
}
public class Manager
{
[System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]
public override void DoSomething()
{ }
}
void main()
{
User user = new User();
user.DoSomething();
Manager manager = new Manager();
manager.DoSomething(); // --------- This row will throw a design time error
}
Удачи:)
Ответ 6
С# не имеет понятия, подобного защищенному или частному наследованию в С++.
Ваш лучший вариант - объединить экземпляр класса и выставить набор методов, которые вас интересуют у вас, у которых есть доступ.
Хотя в вашем случае я не думаю, что это возможно, вы можете изучить создание интерфейса, который предоставляет только общую функциональность, с которой вы хотите работать, чтобы ваша оболочка могла быть заменяемой в некоторых случаях для ее агрегации.
Ответ 7
Я никогда не знал, что вы можете сделать это на С++, хотя я мало знаю о С++. Я боюсь, что я согласен с Blixt, что класс-оболочка - это, вероятно, то, как я это реализую.
Это может сработать (но я не уверен) просто переопределить функцию и выбросить исключение при вызове....
Ответ 8
Насколько я знаю, вы не можете скрыть это так, как хотите. Я думаю, вы могли бы предотвратить его использование любым практическим способом:
class B : A
{
public new void MethodToHide(object param)
{
throw new DontUseThisMethodException();
}
protected void NewMethodInB()
{}
}
Не самая приятная вещь, которую нужно сделать, поэтому вы, вероятно, захотите решить ее каким-то другим способом...
Ответ 9
На самом деле вы можете скрыть метод из C, если бы вы определили метод B как доступный из C.
Единственная проблема с вашим кодом заключается в том, что вы используете "private" в своем объявлении скрытия... если вы используете защищенные или общедоступные, у вас не будет никаких проблем, и он будет работать так, как вы ожидаете. Я делаю это все время с полями.
Ответ 10
Ваш код в производном классе B не будет скрывать базовый метод от всех производных типов, только сам. Вам нужно будет установить метод в личную базу. Единственный способ обойти эту проблему - создать еще один базовый класс, который не раскрывает этот метод.