Java 或 C# 中是否存在强制继承类调用基本实现的构造?您可以调用 super() 或 base() 但如果不调用它是否有可能引发编译时错误?那会很方便..
- 编辑 -
我主要对覆盖方法感到好奇。
Java 或 C# 中是否存在强制继承类调用基本实现的构造?您可以调用 super() 或 base() 但如果不调用它是否有可能引发编译时错误?那会很方便..
- 编辑 -
我主要对覆盖方法感到好奇。
没有也不应该有任何事情可以做到这一点。
如果在基类中有类似的东西,我能想到的最接近的东西:
public virtual void BeforeFoo(){}
public void Foo()
{
this.BeforeFoo();
//do some stuff
this.AfterFoo();
}
public virtual void AfterFoo(){}
并允许继承类覆盖 BeforeFoo 和/或 AfterFoo
不是在 Java 中。这在 C# 中可能是可能的,但其他人将不得不谈论它。
如果我理解正确你想要这个:
class A {
public void foo() {
// Do superclass stuff
}
}
class B extends A {
public void foo() {
super.foo();
// Do subclass stuff
}
}
在 Java 中强制使用超类 foo 可以执行以下操作:
class A {
public final void foo() {
// Do stuff
...
// Then delegate to subclass
fooImpl();
}
protected abstract void fooImpl();
}
class B extends A {
protected void fooImpl() {
// Do subclass stuff
}
}
它很丑陋,但它实现了你想要的。否则,您只需要小心确保调用超类方法。
也许您可以修改您的设计来解决问题,而不是使用技术解决方案。这可能是不可能的,但可能值得考虑。
编辑:也许我误解了这个问题。您是在谈论一般的构造函数或方法吗?我一般假设方法。
以下示例InvalidOperationException
在重写方法时未继承基本功能时引发。
这对于由某些内部 API 调用方法的场景可能很有用。
即 whereFoo()
不是设计为直接调用的:
public abstract class ExampleBase {
private bool _baseInvoked;
internal protected virtual void Foo() {
_baseInvoked = true;
// IMPORTANT: This must always be executed!
}
internal void InvokeFoo() {
Foo();
if (!_baseInvoked)
throw new InvalidOperationException("Custom classes must invoke `base.Foo()` when method is overridden.");
}
}
作品:
public class ExampleA : ExampleBase {
protected override void Foo() {
base.Foo();
}
}
大喊:
public class ExampleB : ExampleBase {
protected override void Foo() {
}
}
您可能想看看这个(称为超级反模式)http://en.wikipedia.org/wiki/Call_super
如果我理解正确,您希望强制您的基类行为不被覆盖,但仍然能够扩展它,那么我将使用模板方法设计模式,并且在 C# 中不要在方法定义中包含 virtual 关键字。
我使用以下技术。请注意,该Hello()
方法是受保护的,所以它不能从外部调用...
public abstract class Animal
{
protected abstract void Hello();
public void SayHello()
{
//Do some mandatory thing
Console.WriteLine("something mandatory");
Hello();
Console.WriteLine();
}
}
public class Dog : Animal
{
protected override void Hello()
{
Console.WriteLine("woof");
}
}
public class Cat : Animal
{
protected override void Hello()
{
Console.WriteLine("meow");
}
}
示例用法:
static void Main(string[] args)
{
var animals = new List<Animal>()
{
new Cat(),
new Dog(),
new Dog(),
new Dog()
};
animals.ForEach(animal => animal.SayHello());
Console.ReadKey();
}
产生:
不,这是不可能的。如果您必须有一个执行某些前或后操作的函数,请执行以下操作:
internal class Class1
{
internal virtual void SomeFunc()
{
// no guarantee this code will run
}
internal void MakeSureICanDoSomething()
{
// do pre stuff I have to do
ThisCodeMayNotRun();
// do post stuff I have to do
}
internal virtual void ThisCodeMayNotRun()
{
// this code may or may not run depending on
// the derived class
}
}
我没有阅读这里的所有回复;但是,我正在考虑同样的问题。在回顾了我真正想做的事情之后,在我看来,如果我想强制调用基本方法,我不应该首先声明基本方法虚拟(可覆盖)。
不要强行进行碱基调用。让父方法做你想做的事,同时在其主体中调用可覆盖(例如:抽象)受保护的方法。
不要以为内置了任何可行的解决方案。不过,我确信有单独的代码分析工具可以做到这一点。
编辑误读构造作为构造函数。保留为 CW,因为它适合问题的一个非常有限的子集。
在 C# 中,您可以通过定义一个在基类型中至少具有一个参数的构造函数来强制执行此行为。这将删除默认构造函数并强制派生类型显式调用指定的基类,否则它们会出现编译错误。
class Parent {
protected Parent(int id) {
}
}
class Child : Parent {
// Does not compile
public Child() {}
// Also does not compile
public Child(int id) { }
// Compiles
public Child() :base(42) {}
}
在 java 中,编译器只能在构造函数的情况下强制执行此操作。
必须在继承链的整个过程中调用构造函数。即,如果 Dog 扩展 Animal 扩展 Thing,则 Dog 的构造函数必须调用 Animal 的构造函数,必须调用 Thing 的构造函数。
这不是常规方法的情况,程序员必须在必要时显式调用超级实现。
强制运行某些基本实现代码的唯一方法是将可覆盖的代码拆分为单独的方法调用:
public class Super
{
public final void doIt()
{
// cannot be overridden
doItSub();
}
protected void doItSub()
{
// override this
}
}
public class Sub extends Super
{
protected void doItSub()
{
// override logic
}
}
我偶然发现了这篇文章,不一定喜欢任何特定的答案,所以我想我会提供自己的...
C# 中没有办法强制调用基本方法。因此,这样的编码被认为是一种反模式,因为后续开发人员可能没有意识到他们必须调用基方法,否则该类将处于不完整或错误状态。
但是,我发现需要这种类型的功能并且可以相应地实现的情况。通常派生类需要基类的资源。为了获取通常可能通过属性公开的资源,它改为通过方法公开。派生类别无选择,只能调用方法获取资源,从而确保执行基类方法。
人们可能会问的下一个合乎逻辑的问题是为什么不把它放在构造函数中呢?原因是它可能是操作顺序问题。在构建类时,可能仍然缺少一些输入。
这是否脱离了问题?是和不是。是的,它确实强制派生类调用特定的基类方法。不,它不会使用 override 关键字来执行此操作。这可能对寻找这篇文章答案的个人有帮助吗?
我不是把它当作福音来宣讲,如果有人看到这种方法的缺点,我很想听听。
在 Android 平台上有一个名为“CallSuper”的 Java 注释,它强制在编译时调用基本方法(尽管这个检查非常基础)。可能相同类型的机制可以在 Java 中以相同的方式轻松实现。https://developer.android.com/reference/androidx/annotation/CallSuper