Basic
Basic

Reputation: 26766

Polymorphic generics

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

Answers (1)

recursive
recursive

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

Related Questions