Why does this C# class declaration compile?

2019-06-16 17:56发布

问题:

This question really is kinda pointless, but I'm just curious:

This:

public sealed class MyClass
{
   protected void MyMethod(){}
}

compiles, but gives a warning

while This:

public sealed class MyClass
{
   public virtual void MyMethod(){}
}

doesn't compile. Just out of sheer curiosity, is there a reason for this?

回答1:

The only reason I can think of is that sometimes you would need to write protected methods to override other protected methods. The language could have been designed to allow this:

protected override void Foo()

but not this

protected void Foo()

but that might have been seen to be a little hard to follow - it's the absence of override which makes it useless, whereas in the case of

public virtual void Foo()

it's the presence of virtual that is useless. The presence of something "wrong" is probably easier to understand than the absence of something useful.

In this case, being virtual may also have performance implications, whereas making something protected instead of private probably doesn't - so it's a bit more severe.

These are just guesses though really - if we're really lucky, Eric Lippert will give a more definitive answer. He's the one you want, not me :)

Best answer: treat warnings as errors and they're equivalent anyway ;)



回答2:

virtual is used to declare a method/property "override-able".

sealed is used to declare that class cannot be inherited from.

So a virtual method in a sealed class could never be overridden, as the class could never be inherited from. It just doesn't make sense.

protected affects access to a member, it does not declare it "override-able" as virtual does (though it is often used in that manner) and is accordingly not contradictory.



回答3:

I can't see a good reason for this. The protected MyMethod can be called from MyClass, but will never be called from a derived class (because MyClass is sealed). The virtual version is also allowed to be called directly from MyClass, but it is illegal for the method to have an override because you can't derive a class from MyClass...



回答4:

A sealed class can have protected members via inheritance. When a method is part of a class, it doesn't matter how that method got there.

In the first case, with the protected method on the sealed class, its the same as if the sealed class inherited a protected method. So it compiles.

Out of curiosity, what exactly is the warning given?



回答5:

The error is:

CS0549: 'function' is a new virtual member in sealed class 'class'.

First of all, despite the fact that it doesn't really make sense to include new protected or virtual members in a sealed class, the CLI¹ does allow it. The CLI also allows calling members of a sealed class using the callvirt IL instruction, even though a compiler could freely replace it with the call instruction.

Currently, I can't find anything in ECMA-334 (C# Language Specification) that requires the compiler emit the above error. It appears like a Microsoft's implementation added the error just because it doesn't make sense to include new virtual members in a sealed class.

¹The CLI is a virtual machine, and the C# compiler emits byte code that runs on it. Almost any concept that's illegal in the CLI is also illegal in C# for that reason - but this is a case where C# does a little extra (not that it's a problem).

Edit: It seems to posts getting marked up are explaining why it doesn't make sense to write code like that in the OP. But regarding what rule made it a compiler error they appear to be wrong.



回答6:

A sealed class cannot be sub-classed, therefore virtual is not an option. Thus error.

This first is a bit silly but valid, thus warning.



回答7:

I'd guess the compiler does some optimizations with sealed classes that are impossible if you have a virtual method declared - "not having a vtable" seems a likely candidate.

That's just a guess, though.



回答8:

As sealed When applied to a class, the sealed modifier prevents other classes from inheriting from it.

here i am trying to explain you one by one:

public sealed class MyClass
{
   protected void MyMethod(){}
}

it gives you warning because practically it make no sense because after declaring a class as sealed you can't inherits it and as your method is protected so you can't access it outside the class using it's object(and keep also in mind that you can't create a child class of this so you can't use this method by that trick also).So practically it makes no sense to making it protected so compiler gives you a warning but if you make it as public or internal then it will not gives you error because it's useful in that case.

now the second one:

public sealed class MyClass
{
   public virtual void MyMethod(){}
}

as you sealed you class and now you are making your method as virtual so indirectly you are giving a offer to someone to override it and that can be only possible by inheritance and here comes the issue.That you class is sealed so you can't perform inheritance with this class.so that's why with virtual it gives error.

i hope it will help you to understand.

for reference http://msdn.microsoft.com/en-us/library/88c54tsw.aspx



回答9:

Declaring a new protected member implies an intent to share that member with descendent classes. A sealed class cannot have descendents, so declaring a new protected member is a bit of an oxymoron, just as declaring a new virtual method in a sealed class.

As for why virtual produces an error while protected only produces a warning, I can only speculate that perhaps it has to do with the fact that new virtual methods require the compiler to build data structures for the type (a vtable), whereas new protected members only have an access flag set - no new data structure. If the compiler is prohibited from creating a vtable for a sealed class, what should it do if it encounters a new virtual method? Fail the compile. A new protected method in a sealed class is pointless but doesn't required the compiler to venture into forbidden territory.



标签: c# .net sealed