为什么在实现接口方法时允许使用 virtual?
我对接口有一个特定的查询。
默认情况下,接口方法是抽象和虚拟的,因此如果我们实现该接口并在类中给出定义,我们实际上会覆盖该方法,但是当我们在实现类中再次将该方法标记为虚拟时,为什么编译器不考虑我们实际上正在尝试隐藏原来接口的虚方法。
就像我们在基类中有一个虚方法,而派生类再次将该方法标记为虚方法一样,在这种情况下,编译器会警告您正在隐藏基类方法,因此如果您有意隐藏基类方法,请使用 new 。
public interface ITestInterface
{
void virtualmethod(); // this method is by default virtual.
}
public class TestInterface :ITestInterface
{
public virtual void virtualmethod()
{
// Now compiler should consider that i am actually hiding the interface virtual method.
}
}
如果您构建上述界面代码并在 ILDASM 中打开,您将看到如下代码:
.method public hidebysig newslot abstract virtual
instance void virtualmethod() cil managed
{
}//end of method ITestInterface::virtualmethod
I have one specific query with the interfaces.
By default interface methods are abstract and virtual so if we implement that interface and gives definition in the class we actually override that method but when we mark the method as a virtual again in the implementing class why the compiler is not considering that we are actually trying to hide the original interface virtual method.
Like if we have a virtual method in the base class and derived class again marked the method as virtual in that case compiler gives the warning that you are hiding the base class method so use new if you are intentionally hiding the base class method.
public interface ITestInterface
{
void virtualmethod(); // this method is by default virtual.
}
public class TestInterface :ITestInterface
{
public virtual void virtualmethod()
{
// Now compiler should consider that i am actually hiding the interface virtual method.
}
}
if you build the above code for interface and open in ILDASM you will see the code like this:
.method public hidebysig newslot abstract virtual
instance void virtualmethod() cil managed
{
}//end of method ITestInterface::virtualmethod
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
默认情况下,从接口实现的方法不是虚拟的。您只是提供接口定义中定义的契约的实现。通过将该方法标记为
虚拟
,您可以允许派生类提供附加或单独的实现,同时仍然遵守所定义的约定。考虑这个例子:
Dog
类通过提供合约IAnimal
的实现来实现接口。这里没有虚拟方法,也没有重写。现在考虑这个示例:
现在
Dog
类已将Speak
声明为virtual
,这允许派生类提供附加或新的实现。这不会破坏与IAnimal
的约定,因为对Speak
方法的任何调用仍然返回一个字符串。好的,最后一个例子。请记住,接口不需要实现 - 它们只需要满足契约。这意味着接口只关心实现类中是否存在具有匹配签名的成员。这意味着我们也可以这样做:
现在请注意,
Dog
类根本没有为Speak
提供任何实现,但已经满足了契约的要求。接口也在类之间继承,因此在上面的所有示例中,
Dog
和GoldenRetriever
都实现了IAnimal
接口。两个类都隐藏Speak
方法 - 两个类都实现它。好吧,我认为您的困惑可能来自于虚拟方法是在接口中定义的,而不是在类中定义的。以下是我上面定义的接口的 IL:
虽然您正确地认为该方法被定义为
virtual
,但您还需要注意,此处的类型被指定为interface
。这纯粹是 Microsoft 的 C# 编译器生成的 MSIL 的实现细节 - 只要在语义上提供相同的结果,另一个编译器就可以轻松生成不同的代码。这里重要的是:即使该方法在接口中声明为虚拟方法,并不意味着它与类中声明的虚拟方法相同。
Methods that are implemented from an interface are not virtual by default. You are merely providing an implementation of the contract defined in the interface definition. By marking the method as
virtual
, you are allowing derived classes to provide additional or separate implementation while still honoring the contract as defined.Consider this example:
The
Dog
class is implementing the interface by providing an implementation of the contractIAnimal
. There are no virtual methods here and no overriding.Now consider this example:
Now the
Dog
class has declaredSpeak
to bevirtual
which allows derived classes to provide an additional or new implementation. This does not break the contract withIAnimal
as any call to theSpeak
method still returns a string.Ok, one last example. Remember that interfaces don't require an implementation - they only require that the contract is satisfied. This means that the interface only cares that a member exists in the implementing class that has a matching signature. This means that we could also do this:
Notice now that the
Dog
class provides no implementation at all forSpeak
yet has satisfied the requirements of the contract.Interfaces are also inherited from class to class so in all the examples above both
Dog
andGoldenRetriever
implement theIAnimal
interface. Neither class hide theSpeak
method - both classes implement it.Ok, I think your confusion may be coming from the fact that the virtual method is defined in an interface, not a class. Here is the IL for the interface I defined above:
While you are correct that the method is defined as
virtual
you also need to notice that the type here is designated as aninterface
. This is purely an implementation detail of the MSIL generated by Microsoft's C# compiler - another compiler could easily generate different code as long as semantically it provided the same result.The important thing here is this: even though the method is declared as
virtual
in the interface that does not mean that it is the same thing as avirtual
method declared in class.这里,IL 和 C# 混淆了术语“虚拟”。
它们并不完全对应。 IL 意义上的虚拟意味着通过 VMT(虚拟方法表)“间接调用”,这与类重写和接口实现的机制大致相同。
在 IL 意义上,接口成员必须标记为虚拟 - 没有办法解决。
但如果你查看实现,它被标记为“虚拟最终”。这是 C# 无法实现的。 “最终”意味着,它不能被覆盖。它不会成为 C# 意义上的虚拟,除非您在 C# 中手动将其声明为“虚拟”或“抽象”。
C# 的隐式接口实现(VB.NET 或 IL 中不存在)非常强大。它确实附加了实现类的方法,该方法在名称-参数-返回值(签名,或 IL 措辞中的 SigAndName)中匹配。
这包括使用方法的基类实现。
这实际上工作得很好。
但C#在这里做了一个技巧,因为你使用BaseClass.MethodC作为接口实现,它在BaseClass中被标记为final virtual。
是的,BaseClass如何实现,取决于BaseClass如何使用。
BaseClass.MethodC 被修改,因为它用于在派生类中实现 ITest.MethodC。只要 BaseClass 的源代码位于同一解决方案中,这甚至可以跨越文件和项目边界。
因此,如果您单独编译项目,或者与其他产品一起编译在一个大解决方案中,则项目编译的输出是不一样的。这是很明显的。
如果BaseClass的源代码不可用,如果您只是链接到DLL中,那么C#将生成一个Wrapper来使用BaseClass实现。
它实际上会这样做:
这是秘密完成的,但绝对有必要将一个方法标记为 IL 意义上的虚拟方法。
There is a mix-up of the term 'virtual' here, between IL and C#.
They do not completely correspond. Virtual in the IL sense means "it's called indirect" via a VMT(virtual method table), that is about the same mechanism for class overriding and interface implementation.
In the IL sense, an interface member must be marked virtual - there is no way around.
But if you look in the implementation, it's marked as 'virtual final'. That is something you cannot achieve in C#. 'Final' means, it cannot be overriden. It does not become virtual in the meaning of C#, unless you declare it manually as 'virtual' or 'abstract' in C#.
The implicit interface implementation of C# (it doesn't exist in VB.NET or IL) is quiet powerful. It does attach the Method of the implementing class, that matches in Name-Parameters-ReturnValue (the Signature, or SigAndName in the IL wording).
This includes using base class implementations for the methods.
This actually works fine.
But C# is doing a Trick here, Cause you use the BaseClass.MethodC as an interface implementation, it's marked as final virtual in the BaseClass.
Yes, the way how BaseClass is implemented, depends on how BaseClass is used.
BaseClass.MethodC is modified, cause it's used to implement ITest.MethodC in a derived class. This even works over file and project boundaries, as long as the source code of BaseClass is in the same solution.
So the output of the compilation of a project, is not the same, if you compile it by itself, or in a big solution together with other products. This is quiet noticable.
If the source code of BaseClass is not available, if you just linked into a DLL, then C# will generate a Wrapper to use the BaseClass implementation.
It will actually do this:
This is done in secret, but it's absolutely necessary to have a method marked as virtual in the IL sense.
接口不是基类,因此不会覆盖实现方法。接口仅声明方法,接口方法默认不是虚拟的,事实上接口仅声明实现该接口的类上可用的方法。
声明不能是虚拟的。
实现可以或不能是虚拟的,完全取决于实现者的逻辑。
Interface is not Base Class, so implementation methods are not overriden. Interface only declares the methods, Interface methods are not virtual by default, infact interfaces only declare the methods that are available on the class that implements that interface.
Declaration can not be virtual.
Implementation can or cannot be virtual that is completely dependent on the implementer's logic.