I have a class hierarchy:
class C1 { virtual object M1(); } class C2: C1 { override sealed object M1(); } class C3: C2 {
But there seems to be a way. In IL, you can override a method with a different name. Thus, we change the name ( M1_2() overrides M1() ), say, overrides the method in the base class ( C1::M1() ), the implementation of the explicit Java interface and the โfinalโ on the intermediate ( C2 ) class no longer matter .
.class public auto ansi beforefieldinit N.C3 extends N.C2 { .method private hidebysig virtual final instance object M1_2() cil managed { .override N.C1::M1
ILasm will happily collect it, and it shows in ILSpy how
public class C3 : C2 { object C1.M1_2()
Then in the same class you can define new M1 that calls this.M1_2() . So you have 1) an overridden M1 (with a different name, but still ...) and 2) there is an M1 method in C3 (this is a "bridge", but this is what you see).
But it looks ... wrong. Or is it something legal?
If you call
C1 obj = new C3(); obj.M1();
then M1_2 is called correctly (I checked it in the debugger). It seems that the CLR applies the final constraint only if the chain is straight ( C1::M1 > C2::M1 > C3::M1 ), and not if you are "jumping" through the hierarchy ( C1::M1 > C3::M1_2 ). You must choose a different name. If you use the same name (M1):
.class public auto ansi beforefieldinit N.C3 extends N.C2 { .method private hidebysig virtual final instance object M1() cil managed { .override N.C1::M1
will not work throwing a System.TypeLoadException
Additional information: The declaration mentioned in the implementation of the method cannot be the final method. What is quite expected.
I wonder: are these CLR rules, or did I just find the cornerstone case in the implementation? (The corner case in the rules will be in order, in the implementation .. you cannot count on it;))