非抽象类中的抽象方法

Ash*_*ain 41 c# compiler-construction oop

我想知道在非抽象类中限制抽象方法的设计背后的原因(在C#中).

我知道类实例不具有定义,因此它们不可调用,但是当定义静态方法时,它们也被排除在实例之外.为什么抽象方法没有这样处理,任何具体原因相同?

可以在具体类中允许它们,并且可以强制派生类实现方法,基本上就是在抽象类中抽象方法的情况下完成的方法.

svi*_*ick 46

首先,我认为你提出的问题在逻辑上并不合理.如果你有abstract方法,它基本上意味着该方法未完成(如@ChrisSinclair指出).但这也意味着整个班级尚未完成,所以它也必须如此abstract.

或者另外一种方式:如果你有abstract一个不是的类的方法abstract,那就意味着你有一个无法调用的方法.但这意味着该方法没有用,您可以将其删除,它将全部工作相同.

现在,我将通过一个例子尝试更具体:想象下面的代码:

Animal[] zoo = new Animal[] { new Monkey(), new Fish(), new Animal() };

foreach (Animal animal in zoo)
    animal.MakeSound();
Run Code Online (Sandbox Code Playgroud)

这里Animal是非abstract基类(这就是为什么我可以将它直接放入数组中),Monkey并且Fish派生自AnimalMakeSound()abstract方法.这段代码应该怎么做?你没有说清楚,但我可以想象几个选择:

  1. 您不能调用MakeSound()类型变量Animal,只能使用类型化的变量作为派生类之一调用它,因此这是一个编译错误.

    这不是一个好的解决方案,因为整个问题abstract是能够将派生类的实例视为基类,并且仍然可以获得特定于派生类的行为.如果你想要这个,只是把一个正常(无abstract,virtualoverride)方法为每个派生类,不要做与基类的东西.

  2. 您不能调用MakeSound()实际运行时类型的对象Animal,因此这是运行时错误(例外).

    这也不是一个好的解决方案.C#是一种静态类型的语言,所以它试图在编译时捕获诸如"你不能调用这个方法"之类的错误(有明显的例外,比如反射和dynamic),所以把它变成运行时错误不适合其余的语言.此外,您可以通过virtual在基类中创建抛出异常的方法来轻松完成此操作.

总而言之,你想要一些没有多大意义的东西,糟糕的设计气味(基类的行为与派生类不同),并且可以很容易地解决.这些都是应该实现的功能的所有内容.


Aak*_*shM 12

所以,你想要允许

class C { abstract void M(); }
Run Code Online (Sandbox Code Playgroud)

编译.假设它确实如此.那么当有人这么做时你会想要发生什么?

new C().M();
Run Code Online (Sandbox Code Playgroud)

?你想要一个执行时错误?好吧,通常C#将编译时错误更喜欢执行时错误.如果您不喜欢这种理念,可以使用其他语言...