English 中文(简体)
强制基本方法调用
原标题:Force base method call

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调用该方法的场景可能很有用。

Foo()未被设计为直接调用:

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() {
    }
}

我使用以下技巧。请注意,<code>Hello()</code>方法是受保护的,因此不能从外部调用它。。。

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();
}

其产生:

您可能想看看这个(调用超级反模式)http://en.wikipedia.org/wiki/Call_super

如果我理解正确,你想强制你的基类行为不被覆盖,但仍然能够扩展它,那么我会使用模板方法设计模式,在C#中,不要在方法定义中包括虚拟关键字。

不,这是不可能的。如果你必须有一个函数来执行一些操作前或操作后操作,请执行以下操作:

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

我没有阅读这里的所有回复;然而,我在考虑同样的问题。在回顾了我真正想做的事情后,我觉得如果我想强制调用基方法,我一开始就不应该声明基方法为virtual(可重写)。

不要强行进行基本呼叫。使父方法执行您想要的操作,同时在其主体中调用可重写(例如:抽象)的受保护方法。

不要认为内置了任何可行的解决方案。不过,我确信有单独的代码分析工具可以做到这一点。

编辑错误读取构造作为构造函数。保留为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





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签