views:

27

answers:

3

Consider a MyForm class that contains a shadowed implementation of Show(), and a CreateForm() method that accepts an instance of the form and calls the shadowed sub:

Public Class MyForm
    Inherits Form

    Public Shadows Sub Show()
        MessageBox.Show("Shadowed implementation called!")
    End Sub
End Class

...

Public Sub CreateForm(ByVal childForm As MyForm)
    childForm.MdiParent = Me
    childForm.Show()
    childForm.Focus()
End Sub

When called with CreateForm(New MyForm()), the shadowed implementation of Show() is correctly called. Now consider the following generic implementation:

Public Sub CreateForm(Of T As Form)(ByVal childForm As T)
    childForm.MdiParent = Me
    childForm.Show()
    childForm.Focus()
End Sub

Called with CreateForm(Of MyForm)(New MyForm()), this strongly-typed generic method never invokes the shadowed method.

Is this a bug, or am I missing something?

+2  A: 

You're missing something. It only knows that it is dealing with a Form at compile-time (remember that generics are not templates!). The only thing you can do is use (override) virtual methods instead of shadowing them.

See also http://stackoverflow.com/questions/463209/shadows-vs-overrides-in-vb-net for more info on shadowing - that's not actually polymorphism.

Lucero
Wouldn't that mean that a generic defined like `SomeMethod(Of T)(ByVal arg As T)` would always have an argument of type `Object`? My call to the generic method explicitly states the type as `MyForm`, so I thought the compiler should be able to infer the argument type. In fact, that seems to be the normal behavior...?
Rob
Nevermind, I understand now. :)
Rob
+1  A: 

It's not a bug because the call is evaluated by the compiler statically based just on the given type constraints applied to T, that is Form. The compiler cannot predict the actual type could contain a shadowed method declaration or whatever other method not declared in the known parent (i.e. Form).

Ondrej Tucny
+2  A: 

This behavior is "By Design". The trick to remember here is that the generic method is compiled and verified by itself (not in the context of the caller as is done in C++). Hence the generic method only knows that T is related to Form. It has no knowledge of MyForm and hence correctly binds to methods on Form.

This is correct because Shadows methods only come into play with the type of the reference at compile time makes the Shadow method visible. This is not the case here as the reference type at compile type is Form (not MyForm). This is in contrast to Overridable where the behavior changes based on the runtime type.

JaredPar
This makes sense, but I'm still not understanding how/why the context of the caller has no bearing on the argument type. Wouldn't that mean that a generic defined like `SomeMethod(Of T)(ByVal arg As T)` would always have an argument of type `Object`?
Rob
@Rob, from the perspective of binding methods on `arg`, yes it is essentially considered to be `Object`. This line is blurred a bit in VB.Net though as by default option strict is disabled and late binding would occur for non-Object methods.
JaredPar