简体   繁体   English

非抽象类中的抽象方法

[英]Abstract Method in Non Abstract Class

I want to know the reason behind the design of restricting Abstract Methods in Non Abstract Class (in C#).我想知道在非抽象类(在 C# 中)中限制抽象方法的设计背后的原因。

I understand that the class instance won't have the definition and thus they wont be callable, but when static methods are defined,they are excluded from the instance too.我知道类实例没有定义,因此它们不能被调用,但是当定义静态方法时,它们也被排除在实例之外。 Why abstract methods are not handled that way, any specific reason for the same?为什么不以这种方式处理抽象方法,有什么具体原因吗?

They could be allowed in concrete class and the deriving class can be forced to implement methods, basically that is what, is done in case of abstract methods in an abstract class.它们可以在具体类中被允许,并且可以强制派生类实现方法,基本上就是在抽象类中的抽象方法的情况下所做的。

First, I think that what you're asking doesn't logically make sense.首先,我认为您的要求在逻辑上没有意义。 If you have an abstract method, it basically means that the method is unfinished (as @ChrisSinclair pointed out).如果您有abstract方法,则基本上意味着该方法未完成(正如@ChrisSinclair 指出的那样)。 But that also means the whole class is unfinished, so it also has to be abstract .但这也意味着整个类是未完成的,所以它也必须是abstract的。

Or another way to put it: if you had an abstract method on a class that wasn't abstract , that would mean you had a method that cannot be called.或者换一种说法:如果你在一个不是abstract的类上有一个abstract方法,那意味着你有一个不能被调用的方法。 But that means the method is not useful, you could remove it and it would all work the same.但这意味着该方法没有用,您可以将其删除,并且它们都可以正常工作。

Now, I'll try to be more concrete by using an example: imagine the following code:现在,我将尝试通过一个示例更具体:想象以下代码:

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

foreach (Animal animal in zoo)
    animal.MakeSound();

Here, Animal is the non- abstract base class (which is why I can put it directly into the array), Monkey and Fish are derived from Animal and MakeSound() is the abstract method.这里, Animal是非abstract基类(这就是为什么我可以将它直接放入数组中), MonkeyFish是从Animal派生的, MakeSound()abstract方法。 What should this code do?这段代码应该做什么? You didn't state that clearly, but I can imagine few options:你没有说清楚,但我可以想象几个选择:

  1. You can't call MakeSound() on a variable typed as Animal , you can call it only using a variable typed as one of the derived classes, so this is a compile error.您不能对类型为Animal的变量调用MakeSound() ,只能使用类型为派生类之一的变量调用它,因此这是一个编译错误。

    This is not a good solution, because the whole point of abstract is to be able to treat instances of derived classes as the base class, and still get behaviour that's specific to the derived class.这不是一个好的解决方案,因为abstract的全部意义在于能够将派生类的实例视为基类,并且仍然获得特定于派生类的行为。 If you want this, just put a normal (no abstract , virtual or override ) method into each derived class and don't do anything with the base class.如果你想要这个,只需在每个派生类中放入一个普通的(没有abstractvirtualoverride )方法,并且不对基类做任何事情。

  2. You can't call MakeSound() on an object whose runtime type is actually Animal , so this is a runtime error (an exception).您不能在运行时类型实际上是Animal的对象上调用MakeSound() ,因此这是运行时错误(异常)。

    This is also not a good solution.这也不是一个好的解决方案。 C# is a statically typed language and so it tries to catch errors like “you can't call this method” at compile time (with obvious exceptions like reflection and dynamic ), so making this into a runtime error wouldn't fit with the rest of the language. C# 是一种静态类型的语言,因此它会尝试在编译时捕获诸如“您不能调用此方法”之类的错误(反射和dynamic等明显异常),因此将其变成运行时错误将不适合其余部分的语言。 Besides, you can do this easily by creating a virtual method in the base class that throws an exception.此外,您可以通过在引发异常的基类中创建virtual方法来轻松完成此操作。

To sum up, you want something that doesn't make much sense, and smells of bad design (a base class that behaves differently than its derived classes) and can be worked around quite easily.总而言之,您想要一些没有多大意义的东西,并且带有糟糕设计的味道(一个行为与其派生类不同的基类)并且可以很容易地解决。 These are all signs of a feature that should not be implemented.这些都是不应实施的功能的迹象。

So, you want to allow所以,你想允许

class C { abstract void M(); }

to compile.编译。 Suppose it did.假设确实如此。 What do you then want to happen when someone does当有人这样做时,您希望发生什么

new C().M();

? ? You want an execution-time error?您想要执行时错误吗? Well, in general C# prefers compile-time errors to execution-time errors.好吧,通常 C# 更喜欢编译时错误而不是执行时错误。 If you don't like that philosophy, there are other languages available...如果您不喜欢这种哲学,还有其他语言可用...

I think you've answered your own question, an abstract method isn't defined initially.我认为您已经回答了自己的问题,最初没有定义抽象方法。 Therefore the class cannot be instanciated.因此无法实例化该类。 You're saying it should ignore it, but by definition when adding an abstract method you're saying "every class created from this must implement this {abstract method}" hence the class where you define the abstract class must also be abstract because the abstract method is still undefined at that point.您是说它应该忽略它,但是根据定义,在添加抽象方法时,您是在说“由此创建的每个类都必须实现此{抽象方法}”,因此您定义抽象类的类也必须是抽象的,因为那时抽象方法仍未定义。

You can achieve what you want using "virtual" methods but using virtual methods can lead to more runtime business logic errors as a developer is not "forced" to implement the logic in the child class.您可以使用“虚拟”方法实现您想要的,但使用虚拟方法可能会导致更多运行时业务逻辑错误,因为开发人员不会“被迫”在子类中实现逻辑。

I think there's a valid point here.我认为这里有一个有效的观点。 An abstract method is the perfect solution as it would "enforce" the requirement of defining the method body in children.抽象方法是完美的解决方案,因为它将“强制”定义子方法体的要求。

I have come across many many situations where the parent class had to (or it would be more efficient to) implement some logic but "Only" children could implement rest of the logic"我遇到过很多情况,父类必须(或者更有效地)实现一些逻辑,但“只有”孩子可以实现其余的逻辑”

So if the opportunity was there I would happily mix abstract methods with complete methods.因此,如果有机会,我会很乐意将抽象方法与完整方法混合使用。

@AakashM, I appreciate C# prefers compile time errors. @AakashM,我很欣赏 C# 更喜欢编译时错误。 So do I. And so does anybody.我也是。任何人也一样。 This is about thinking out-of-the-box.这是关于开箱即用的思考。

And supporting this will not affect that.支持这一点不会影响这一点。

Let's think out of the box here, rather than saying "hurrah" to big boy decisions.让我们在这里跳出框框思考,而不是对大男孩的决定说“万岁”。

C# compiler can detect and deny someone of using an abstract class directly because it uses the "abstract" keyword. C# 编译器可以直接检测并拒绝某人使用抽象类,因为它使用“abstract”关键字。

C# also knows to force any child class to implement any abstract methods. C# 也知道强制任何子类实现任何抽象方法。 How?如何? because of the use of the "abstract" keyword.因为使用了“抽象”关键字。

This is pretty simple to understand to anyone who has studied the internals of a programming language.对于任何研究过编程语言内部的人来说,这很容易理解。

So, why can't C# detect an "abstract" keyword next to a method in a normal class and handle it at the COMPILE TIME.那么,为什么 C# 不能检测到普通类中方法旁边的“抽象”关键字并在编译时处理它。

The reason is it takes "reworking" and the effort is not worth supporting the small demand.原因是它需要“返工”,付出的努力不值得支持小需求。

Specially in an industry that lacks people who think out of the boxes that big boys have given them.特别是在一个缺乏大男孩给他们的框框思考的人的行业。

The abstract class may contain abstract member.抽象类可能包含抽象成员。 There is the only method declaration if any method has an abstract keyword we can't implement in the same class.如果任何方法具有我们无法在同一个类中实现的抽象关键字,则只有方法声明。 So the abstract class is incompleted.所以抽象类是不完整的。 That is why the object is not created for an abstract class.这就是为什么没有为抽象类创建对象的原因。

Non-abstract class can't contain abstract member.非抽象类不能包含抽象成员。

Example:例子:

namespace InterviewPreparation
{
   public abstract class baseclass
    {
        public abstract void method1(); //abstract method
        public abstract void method2(); //abstract method
        public void method3() { }  //Non- abstract method----->It is necessary to implement here.
    }
    class childclass : baseclass
    {
        public override void method1() { }
        public override void method2() { }
    }
    public class Program    //Non Abstract Class
    {
        public static void Main()
        {
            baseclass b = new childclass(); //create instance
            b.method1();
            b.method2();
            b.method3();
        }
    }

}

It's still not clear why you would want that, but an alternative approach could be to force derived classes to provide a delegate instance.目前尚不清楚您为什么要这样做,但另一种方法可能是强制派生类提供委托实例。 Something like this像这样的东西

class MyConcreteClass
{
  readonly Func<int, DateTime, string> methodImpl;

  // constructor requires a delegate instance
  public MyConcreteClass(Func<int, DateTime, string> methodImpl)
  {
    if (methodImpl == null)
      throw new ArgumentNullException();

    this.methodImpl = methodImpl;
  }

  ...
}

(The signature string MethodImpl(int, DateTime) is just an example, of course.) (当然,签名string MethodImpl(int, DateTime)只是一个示例。)

Otherwise, I can recommend the other answers to explain why your wish probably isn't something which would make the world better.否则,我可以推荐其他答案来解释为什么您的愿望可能不会让世界变得更美好。

So the answers above are correct: having abstract methods makes the class inherently abstract.所以上面的答案是正确的:拥有抽象方法使类本质上是抽象的。 If you cannot instance part of a class, then you cannot instance the class itself.如果你不能实例化一个类的一部分,那么你就不能实例化这个类本身。 However, the answers above didn't really discuss your options here.但是,上面的答案并没有真正讨论您的选择。

First, this is mainly an issue for public static methods.首先,这主要是公共静态方法的问题。 If the methods aren't intended to be public, then you could have protected non-abstract methods, which are allowed in an abstract class declaration.如果这些方法不打算公开,那么您可以保护非抽象方法,这些方法在抽象类声明中是允许的。 So, you could just move these static methods to a separate static class without much issue.因此,您可以将这些静态方法移至单独的静态类,而不会出现太大问题。

As an alternative, you could keep those methods in the class, but then instead of having abstract methods, declare an interface.作为替代方案,您可以将这些方法保留在类中,但随后不使用抽象方法,而是声明一个接口。 Essentially, you have a multiple-inheritance problem as you want the derived class to inherit from two conceptually different objects: a non-abstract parent with public static members, and an abstract parent with abstract methods.本质上,您有一个多重继承问题,因为您希望派生类从两个概念上不同的对象继承:一个具有公共静态成员的非抽象父类,以及一个具有抽象方法的抽象父类。 Unlike some other frameworks, C# does permit multiple inheritance.与其他一些框架不同,C# 确实允许多重继承。 Instead, C# offers a formal interface declaration that is intended to fill this purpose.相反,C# 提供了一个正式的接口声明来满足这个目的。 Moreover, the whole point of abstract methods, really, is just to impose a certain conceptual interface.此外,抽象方法的全部意义实际上只是强加了某个概念接口。

I have a scenario very similar to what the OP is trying to achieve.我有一个与 OP 试图实现的非常相似的场景。 In my case the method that I want to make abstract would be a protected method and would only be known to the base class.在我的情况下,我想要抽象的方法将是一个受保护的方法,并且只有基类知道。 So the "new C().M();"所以“新的 C().M();” does not apply because the method in question is not public.不适用,因为所讨论的方法不是公开的。 I want to be able to instantiate and call public methods on the base class (therefore it needs to be non-abstract), but I need these public methods to call a protected implementation of the protected method in the child class and have no default implementation in the parent.我希望能够在基类上实例化和调用公共方法(因此它必须是非抽象的),但是我需要这些公共方法来调用子类中受保护方法的受保护实现并且没有默认实现在父母。 In a manner of speaking, I need to force descendants to override the method.从某种意义上说,我需要强制后代覆盖该方法。 I don't know what the child class is at compile time due to dependency injection.由于依赖注入,我不知道编译时子类是什么。

My solution was to follow the rules and use a concrete base class and a virtual protected method.我的解决方案是遵循规则并使用具体的基类和虚拟保护方法。 For the default implementation, though, I throw a NotImplementedException with the error "The implementation for method name must be provided in the implementation of the child class."但是,对于默认实现,我抛出 NotImplementedException 错误“必须在子类的实现中提供方法名称的实现”。

protected virtual void MyProtectedMethod() 
{ 
  throw new NotImplementedException("The implementation for MyProtectedMethod must be provided in the implementation of the child class."); 
}

In this way a default implementation can never be used and implementers of descendant implementations will quickly see that they missed an important step.通过这种方式,永远不能使用默认实现,并且后代实现的实现者很快就会发现他们错过了重要的一步。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM