VB.Net Inheritance and Interfaces
Has someone a hint what I'm doing wrong in VB.Net?
Module Module1
Interface ISearch(Of T As ISearchResult)
Function ids() As List(Of T)
End Interface
Interface ISearchResult
Function id() As String
End Interface
MustInherit Class BasicSearch(Of T As ISearchResult)
Implements ISearch(Of T)
MustOverride Function ids() As System.Collections.Generic.List(Of T) Implements ISearch(Of T).ids
End Class
Class Search
Inherits BasicSearch(Of SearchResult)
Implements ISearch(Of SearchResult)
Overrides Function ids() As System.Collections.Generic.List(Of Searc开发者_C百科hResult)
Return New List(Of SearchResult)
End Function
End Class
Class SearchResult
Implements ISearchResult
Public Function id() As String Implements ISearchResult.id
Return "id"
End Function
End Class
Sub Main()
Dim foo As New Search()
Dim bar As Object = foo
Dim foobar As ISearch(Of ISearchResult) = foo
End Sub
End Module
The third cast isn't working. Why?
did I miss a oop lesson?
thanks
An ISearch(Of SearchResult)
isn't an ISearch(Of ISearchResult)
- they have different generic type parameters. Search
is an ISearch(Of SearchResult)
.
Brian's answer covers the covariance, etc, stuff for .NET 4 that I'd planned to add to this question later (I wrote the initial answer quickly and then had to go offline - by the time I got back, Brian had answered)
To answer mr. moes comment - Imagine if ISearch
had another method:
Sub AddID(ID as T)
and assuming we then implement that in Search
(which, remember, is ISearch(Of SearchResult)
, so T
is SearchResult
). And assume we had something else that implements ISearchResult
, say:
Public Class BadNews
Implements ISearchResult
Public Function id() As String Implements ISearchResult.id
Return "other"
Function
End Class
Now, if your cast worked, we could now call:
foobar.AddID(New BadNews)
But this can't work - the implementation of AddID
that we're calling is the one implemented by Search
- and that function is only expecting to receive objects of type SearchResult
.
The cast does not work because foobar
is a ISearch(Of ISearchResult)
and foo
is a ISearch(Of SearchResult
which are not compatible and no implicit conversion operator exists.
.NET 4.0 introduced the concept of covariant and contravariant generic type parameters which can be used to solve this problem elegantly. If you tried to compile the code with VB 10 you would get this error.
error BC36757: 'Module1.Search' cannot be converted to 'Module1.ISearch(Of Module1.ISearchResult)'. Consider changing the 'T' in the definition of 'Interface ISearch(Of T As Module1.ISearchResult)' to an Out type parameter, 'Out T'.
Following the recommendation you can indicate that T
is covariant in ISearchResult
by using the new Out
keyword.
Interface ISearch(Of Out T As ISearchResult)
Function ids() As List(Of T)
End Interface
Unfortunately we now get this error.
error BC36724: Type 'T' cannot be used in this context because 'T' is an 'Out' type parameter.
The reason is because List(Of T)
is not covariant itself. However, IEnumerable(Of T)
is. So this would be okay.
Interface ISearch(Of Out T As ISearchResult)
Function ids() As IEnumerable(Of T)
End Interface
You would then need to make the same change from List(Of T)
to IEnumerable(Of T)
for the other declarations as well.
精彩评论