// Cannot change source code
class Base
{
public virtual void Say()
{
Console.WriteLine("Called from Base.");
}
}
// Cannot change source code
class Derived : Base
{
public override void Say()
{
Console.WriteLine("Called from Derived.");
base.Say();
}
}
class SpecialDerived : Derived
{
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
}
class Program
{
static void Main(string[] args)
{
SpecialDerived sd = new SpecialDerived();
sd.Say();
}
}
Результат:
Вызывается из Special Derived.
Вызывается из Derived. / * этого не ожидается * /
Вызывается с базы.
Как я могу переписать класс SpecialDerived так, чтобы метод среднего класса "Derived" не вызывался?
ОБНОВЛЕНИЕ:
причина, по которой я хочу унаследовать от Derived вместо Base, - это класс Derived, который содержит множество других реализаций. Поскольку я не могу сделать base.base.method()
здесь, я думаю, что лучше всего сделать следующее?
// Невозможно изменить исходный код
class Derived : Base
{
public override void Say()
{
CustomSay();
base.Say();
}
protected virtual void CustomSay()
{
Console.WriteLine("Called from Derived.");
}
}
class SpecialDerived : Derived
{
/*
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
*/
protected override void CustomSay()
{
Console.WriteLine("Called from Special Derived.");
}
}
c#
polymorphism
AZ.
источник
источник
Ответы:
Просто хочу добавить это здесь, поскольку люди все равно возвращаются к этому вопросу даже спустя много времени. Конечно, это плохая практика, но все же можно (в принципе) делать то, что хочет автор:
источник
Func<stuff>
вместоAction
Это плохая практика программирования и недопустима в C #. Это плохая практика программирования, потому что
Детали grandbase - это детали реализации базы; на них не стоит полагаться. Базовый класс предоставляет абстракцию поверх grandbase; вы должны использовать эту абстракцию, а не строить обходной путь, чтобы избежать этого.
Чтобы проиллюстрировать конкретный пример предыдущего пункта: если он разрешен, этот шаблон будет еще одним способом сделать код уязвимым для сбоев хрупкого базового класса. Предположим
C
производное отB
которого производноеA
. Код вC
использованииbase.base
для вызова методаA
. Затем авторB
понимает, что они вложили в класс слишком много снаряженияB
, и что лучший подход - создать промежуточный класс,B2
который является производнымA
иB
производным отB2
. После этого изменения код вC
вызывает метод вB2
, а не вA
, потому чтоC
автор сделал предположение, что детали реализацииB
, а именно, что его прямой базовый классA
, никогда не изменится. Многие проектные решения в C # призваны снизить вероятность различных видов хрупких отказов основания; решение сделатьbase.base
незаконным полностью предотвращает эту особую разновидность паттерна отказа.Вы заимствовали свою базу, потому что вам нравится то, что она делает, и вы хотите ее повторно использовать и расширять. Если вам не нравится то, что он делает, и вы хотите обойти это, а не работать с этим, то почему вы вообще взяли это? Сами извлеките из grandbase те функции, которые вы хотите использовать и расширить.
Базе могут потребоваться определенные инварианты для целей безопасности или семантической согласованности, которые поддерживаются деталями того, как база использует методы большой базы. Разрешение производному классу базы пропускать код, поддерживающий эти инварианты, может привести базу в несогласованное, поврежденное состояние.
источник
Вы не можете с C #. В IL это действительно поддерживается. Вы можете сделать вызов любого из ваших родительских классов без поддержки virt ... но, пожалуйста, не делайте этого. :)
источник
Ответ (я знаю, что это не то, что вы ищете):
По правде говоря, у вас есть прямое взаимодействие только с классом, от которого вы наследуете. Думайте об этом классе как о слое, предоставляющем его производным классам столько или меньше, сколько он желает, либо его родительских функций.
РЕДАКТИРОВАТЬ:
Ваше редактирование работает, но я бы использовал что-то вроде этого:
Конечно, в реальной реализации вы могли бы сделать что-то подобное для расширяемости и ремонтопригодности:
Затем производные классы могут соответствующим образом управлять состоянием своих родителей.
источник
Derived
которой вызываетсяBase.Say
, чтобы ее можно было вызыватьSpecialDerived
? Проще, не так ли?Почему бы просто не привести дочерний класс к определенному родительскому классу и затем вызвать конкретную реализацию? Это особая ситуация, и следует использовать особое решение. Однако вам придется использовать
new
ключевое слово в дочерних методах.источник
источник
Вы также можете сделать простую функцию в производном классе первого уровня, чтобы вызвать большую базовую функцию
источник
Мой 2c для этого - реализовать функциональность, которая вам требуется для вызова в классе инструментария, и вызывать ее из любого места, где вам нужно:
Это требует некоторых размышлений относительно прав доступа, вам может потребоваться добавить некоторые
internal
методы доступа для облегчения функциональности.источник
В случаях, когда у вас нет доступа к источнику производного класса, но вам нужен весь источник производного класса, кроме текущего метода, я бы рекомендовал вам также создать производный класс и вызвать реализацию производного класса.
Вот пример:
источник
Как видно из предыдущих сообщений, можно утверждать, что если функциональность класса необходимо обойти, значит, что-то не так в архитектуре класса. Это может быть правдой, но не всегда можно реструктурировать или реорганизовать структуру классов в большом зрелом проекте. Различные уровни управления изменениями могут быть одной проблемой, но сохранение существующей функциональности после рефакторинга не всегда является тривиальной задачей, особенно если применяются временные ограничения. В зрелом проекте может быть непросто предотвратить прохождение различных регрессионных тестов после реструктуризации кода; часто возникают неясные "странности". У нас была аналогичная проблема, в некоторых случаях унаследованные функции не должны выполняться (или должны выполнять что-то еще). Подход, который мы использовали ниже, было поместить базовый код, который нужно исключить, в отдельную виртуальную функцию. Затем эту функцию можно переопределить в производном классе, а ее функциональность исключить или изменить. В этом примере «Текст 2» можно запретить выводить в производном классе.
источник
Кажется, существует много этих вопросов, связанных с наследованием метода-члена от класса Grandparent, переопределением его во втором классе, а затем повторным вызовом его метода из класса Grandchild. Почему бы просто не унаследовать члены дедушки и бабушки внукам?
Кажется простым .... здесь внук наследует метод дедушки и бабушки. Подумайте об этом ... вот как "Object" и его члены, такие как ToString (), наследуются всем классам в C #. Я думаю, что Microsoft не очень хорошо объяснила базовое наследование. Слишком много внимания уделяется полиморфизму и реализации. Когда я копаюсь в их документации, я не вижу примеров этой очень простой идеи. :(
источник
Если вы хотите получить доступ к данным базового класса, вы должны использовать ключевое слово this или использовать это ключевое слово как ссылку для класса.
источник