C# 非抽象类中的抽象方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12581070/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Abstract Method in Non Abstract Class
提问by Ashish Jain
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.
它们可以在具体类中被允许,并且可以强制派生类实现方法,基本上就是在抽象类中的抽象方法的情况下完成的。
采纳答案by svick
First, I think that what you're asking doesn't logically make sense. If you have abstractmethod, it basically means that the method is unfinished (as @ChrisSinclair pointed out). But that also means the whole class is unfinished, so it also has to be abstract.
首先,我认为你问的在逻辑上没有意义。如果您有abstract方法,则基本上意味着该方法未完成(正如@ChrisSinclair 指出的那样)。但这也意味着整个课程尚未完成,因此它也必须是abstract.
Or another way to put it: if you had abstractmethod on a class that wasn't abstract, that would mean you had a method that cannot be called. But that means the method is not useful, you could remove it and it would all work the same.
或者换一种说法:如果你abstract在一个不是的类上有方法abstract,那就意味着你有一个不能被调用的方法。但这意味着该方法没有用,您可以将其删除,并且所有方法都一样。
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, Animalis the non-abstractbase class (which is why I can put it directly into the array), Monkeyand Fishare derived from Animaland MakeSound()is the abstractmethod. What should this code do? You didn't state that clearly, but I can imagine few options:
在这里,Animal是非abstract基类(这就是为什么我可以将它直接放入数组中),Monkey并且Fish派生自Animal和MakeSound()是abstract方法。这段代码应该做什么?你没有说清楚,但我可以想象几个选择:
You can't call
MakeSound()on a variable typed asAnimal, you can call it only using a variable typed as one of the derived classes, so this is a compile error.This is not a good solution, because the whole point of
abstractis to be able to treat instances of derived classes as the base class, and still get behavior that's specific to the derived class. If you want this, just put a normal (noabstract,virtualoroverride) method into each derived class and don't do anything with the base class.You can't call
MakeSound()on an object whose runtime type is actuallyAnimal, so this is a runtime error (an exception).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. Besides, you can do this easily by creating avirtualmethod in the base class that throws an exception.
您不能调用
MakeSound()类型为 的变量Animal,只能使用类型为派生类之一的变量来调用它,因此这是编译错误。这不是一个好的解决方案,因为重点
abstract是能够将派生类的实例视为基类,并且仍然获得特定于派生类的行为。如果你想要这个,只需在每个派生类中放入一个普通的(没有abstract,virtual或override)方法,不要对基类做任何事情。您不能调用
MakeSound()运行时类型实际上为 的对象Animal,因此这是一个运行时错误(异常)。这也不是一个好的解决方案。C# 是一种静态类型语言,因此它会在编译时尝试捕获诸如“您无法调用此方法”之类的错误(有明显的异常,例如反射和
dynamic),因此将其设为运行时错误不适用于其余的语言。此外,您可以通过virtual在基类中创建一个抛出异常的方法来轻松完成此操作。
To sum up, you want something that doesn't make much sense, smells of bad design (base class that behaves differently than its derived classes) and can be worked around quite easily. These are all sings of a feature that should notbe implemented.
总而言之,您想要一些没有多大意义、有不良设计味道的东西(基类的行为与其派生类不同)并且可以很容易地解决。这些都是不应该实现的功能。
回答by AakashM
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. If you don't like that philosophy, there are other languages available...
? 你想要一个执行时错误?嗯,通常 C# 更喜欢编译时错误而不是执行时错误。如果你不喜欢这种哲学,还有其他语言可用......
回答by Dale K
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.
我认为您已经回答了自己的问题,最初没有定义抽象方法。因此该类不能被实例化。您是说它应该忽略它,但是根据定义,在添加抽象方法时,您是说“由此创建的每个类都必须实现此 {abstract method}”,因此您定义抽象类的类也必须是抽象的,因为此时抽象方法仍未定义。
回答by Jeppe Stig Nielsen
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.
否则,我可以推荐其他答案来解释为什么您的愿望可能不会使世界变得更好。
回答by Menol
You can achieve what you want using "virtual" methods but using virtual methods can lead to more runtime business logic errors as a develop 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. So do I. And so does anybody. This is about thinking out-of-the-box.
@AakashM,我很欣赏 C# 更喜欢编译时错误。我也是。任何人也是。这是关于开箱即用的思考。
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# 编译器可以直接检测并拒绝某人使用抽象类,因为它使用了“抽象”关键字。
C# also knows to force any child class to implement any abstract methods. How? because of the use of the "abstract" keyword.
C# 还知道强制任何子类实现任何抽象方法。如何?因为使用了“抽象”关键字。
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.
特别是在一个缺乏能够跳出大男孩给他们的框框思考的人的行业中。
回答by Matthew
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 publicstatic 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. Instead, C# offers a formal interface declaration that is intended to fill this purpose. Moreover, the whole point of abstract methods, really, is just to impose a certain conceptual interface.
作为替代方案,您可以将这些方法保留在类中,然后声明一个接口而不是抽象方法。本质上,您有一个多重继承问题,因为您希望派生类从两个概念上不同的对象继承:一个具有公共静态成员的非抽象父类,以及一个具有抽象方法的抽象父类。与其他一些框架不同,C# 确实允许多重继承。相反,C# 提供了旨在满足此目的的正式接口声明。此外,抽象方法的全部意义实际上只是强加某个概念接口。
回答by Jim K
I have a scenario very similar to what the OP is trying to achieve. In my case the method that I want to make abstract would be a protectedmethod and would only be known to the base class. So the "new 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.
我有一个与 OP 试图实现的场景非常相似的场景。在我的情况下,我想要抽象的方法将是受保护的方法,并且只有基类知道。所以“new C().M();” 不适用,因为所讨论的方法不是公开的。我希望能够在基类上实例化和调用公共方法(因此它需要是非抽象的),但是我需要这些公共方法来调用子类中受保护方法的受保护实现并且没有默认实现在父级。从某种意义上说,我需要强制后代覆盖该方法。由于依赖注入,我不知道子类在编译时是什么。
My solution was to follow the rules and use a concrete base class and a virtual protectedmethod. For the default implementation, though, I throw a NotImplementedException with the error "The implementation for method namemust 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.
通过这种方式,永远无法使用默认实现,后代实现的实现者将很快发现他们错过了重要的一步。
回答by vikas Chaturvedi
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();
}
}
}

