Как скрыть (удалить) методы базового класса в C#? [дубликат]

этот вопрос уже есть ответ здесь:

суть проблемы заключается в том, что при такой иерархии классов:

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's ok
        base.NewMethodInB();
    }
}

как я могу предотвратить любые классы, наследуемые от класса "B", от просмотра метод A.MethodToHide()? В C++ это было достаточно просто, используя объявление, такое как class B : private A, но этот синтаксис недопустим в C#.

для тех, кто заинтересован (или интересно, что я действительно пытается сделать), то, что мы пытаемся сделать, это создать обертку для носорога.Палата общин.NHRepository, который скрывает методы, которые мы не хотим подвергать нашей группе разработчиков, поэтому мы можем иметь способ cookie-cutter разработки нашего приложения, что новые разработчики могут легко следовать. Так что да, я верю "Это-" тест действителен для всей цепи (WidgetRepository это-BaseRepository это-NHRepository).

редактировать: я должен был упомянуть, ради аргумента, что класс A является классом API вне нашего контроля. В противном случае проблема становится значительно легче.

10 ответов


вы не можете сделать это и сохранить иерархию. Если возможно, вы должны создать интерфейсы, которые определяют ваш идеал, затем подкласс базовых классов и реализовать интерфейсы. ссылаться только на интерфейсы (а не на типы базовых классов) в коде.

на шаблон адаптер был создан специально для решения проблемы использования фреймворка, когда его API не соответствует вашим потребностям.


Устарело Это

в классе B переопределите MethodToHide и добавьте устаревший атрибут

[Obsolete("Reason", true)] // true will cause a compile-time error

Установить EditorBrowsable

(Как упоминалось ранее)

в классе B переопределите MethodToHide и добавьте атрибут EditorBrowsable

[System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]

исключения

(Как упоминалось ранее)

в классе B переопределите MethodToHide и throw исключение.

Создать Обертку

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

class B: IInterface
{    
    protected void MethodToExpose()
    {
        A a = new A();
        a.MethodToExpose();
    }

    protected void NewMethodInB()
    {
    }
}

Если вы хотите настроить набор функций, я бы сказал, что вы хотите сделать оболочку, а не наследовать функциональность. Я тоже не знаю, как сделать то, что вы хотите в C#.

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


Если вы используете Visual Studio, вы можете скрыть методы / свойства из intelliprompt с помощью этого атрибута:

class A
{
    protected void MethodToExpose()
    {}

    [System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]
    protected void MethodToHide(object param)
    {}
}

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


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

просто добавьте этот код поверх своего метода:

[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
}

Удачи :)


C# не имеет понятия, аналогичного защищенному или частному наследованию в C++.

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

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


Я никогда не знал, что вы можете сделать это на C++, хотя я мало знаю о C++. Боюсь, что я согласен с Blixt, что a класса вероятно, как я бы это реализовал.

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


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

class B : A
{
    public new void MethodToHide(object param)
    { 
        throw new DontUseThisMethodException();
    }

    protected void NewMethodInB()
    {}
}

Не самая приятная вещь, поэтому вы, вероятно, захотите решить ее каким-то другим способом...


на самом деле вы можете скрыть метод A от C, если бы вы определили метод B как доступный из C.

единственная проблема с вашим кодом заключается в том, что вы используете "private" в своем объявлении скрытия... если вы используете protected или public, у вас не будет никаких проблем, и он будет работать так, как вы ожидаете. Я все время так делаю с Филдсом.


ваш код в производном классе B не будет скрывать базовый метод от всех производных типов, только сам. Вам нужно будет установить метод в private на базе. Единственный способ обойти эту проблему-создать другой базовый класс, который не предоставляет этот метод.