Reputation: 26766
I have a generic class Command(Of T)
Command is defined (in part) as:
Public Class Command(Of T As BaseType)
Inherits Command
Public Property Condition As Func(Of T, Boolean)
End Class
I want to create a list of all commands, then when I'm handed an object A
, pull out all commands with the same generic type as my A
for which a call to Condition(A)
returns true
I can do
Dim B As List(Of BaseType)
B.Add(New DerivedType)
But
Dim C As New List(Of Command(Of BaseType))
C.Add(New Command(Of DerivedType))
Throws a conversion error.
I can make Command
inherit from a non-generic object (let's call it CommandBase
...)
Dim C As New List(Of CommandBase)
C.Add(New Command(Of DerivedType))
Which works but now I can't get back to the type-specific reference. This gets the right command objects:
Dim CommandsOfTypeA = B.Where(function(x) x.GetType.GetGenericArguments(0).FullName = A.GetType.FullName)
But I can't now see how to do...
Dim MatchingCommands = CommandsOfTypeA.Where(function(x) c.Condition(A))
As CommandsOfTypeA is a List(Of Command)
not List(Of Command(Of DerivedType))
What am I missing?
Upvotes: 3
Views: 183
Reputation: 86074
The problem is that while an an instance of DerivedType
is an instance of BaseType
, that doesn't necessarily mean that an instance of Command(Of DerivedType)
is an instance of Command(Of BaseType)
. By default, type hierarchies are not considered for generic type parameters.
In programming language theory, the feature that enables this is called covariance.
.net 4.0 does have some support for this, although it can only be applied to interfaces, not classes. Here is some documentation on the subject.
Basically, it looks like this:
Interface ICovariant(Of Out R)
Function GetSomething() As R
' The following statement generates a compiler error.
' Sub SetSomething(ByVal sampleArg As R)
End Interface
This only works (as illustrated) when your generic type is only used as method inputs, never outputs, or ref
or output
parameters.
Upvotes: 1