I am trying to cast a type into an interface and have some problems with it

Daniel Bischof 20 Reputation points
2023-01-24T18:15:52.9266667+00:00

Hi guys! I have the following code snippet that I'm currently trying to reason about. It looks a bit constructed but contains all important assets of the actual code, so please bear with me here :)

Interface ISpark
    Function Swing() As Double
End Interface

Class MySpark : Implements ISpark

    Public Function Swing() As Double Implements ISpark.Swing
        Throw New NotImplementedException()
    End Function
End Class

Interface IMagic(Of T As ISpark)
        Function Method() As T
    End Interface

Class A(Of T As ISpark) : Implements IMagic(Of T)

    Public Function Method() As T Implements IMagic(Of T).Method
        Throw New NotImplementedException()
    End Function
End Class

Class B(Of T As ISpark) : Inherits A(Of T)

End Class

Class TestingClass
    Private MyB As A(Of ISpark)

    Sub Initialize()
        MyB = New B(Of MySpark)
    End Sub
End Class

All works fine but the last assignment into MyB - and I don't really understand why.

Essentially, B inherits from A, MySpark implements ISpark, so the 'boundary conditions' of A(Of ISpark) should be given. Why can't I assign this then?

The situation doesn't change If my class looks like

Class TestingClass
    Private MyB As B(Of ISpark)
    Sub Initialize()
        MyB = New B(Of MySpark)
    End Sub
End Class

Does someone have an idea about how to make a construction like this work? That would be a great help :)

VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,569 questions
{count} votes

Accepted answer
  1. Michael Taylor 48,046 Reputation points
    2023-01-24T22:51:29.4333333+00:00

    This is a common misunderstanding of generic types. It is common for people to associate inheritance with generics because the syntax is similar but that simply isn't the case. Let's eliminate generics for a minute and just look at a simple example.

    Class BaseType
    End Class
    
    Class DerivedType : Inherits BaseType
    End Class
    
    Class DerivedType2 : Inherits BaseType
    End Class
    
    Dim myDerived As DerivedType = New DerivedType2
    

    I think we can agree that this is not valid. You are attempting to assign a DerivedType2 to DerivedType and they aren't compatible. They do share the same base type BaseType but that changes nothing. However this is valid.

    Dim myObj As BaseType = New DerivedType2
    

    Because DerivedType2 derives from BaseType they are compatible. That's exactly how all types work, even generic types. Where people get confused is thinking generic types share a base type because their type parameters do, that is not true. A(Of ISpark) implements the IMagic(Of ISpark) interface which itself has no base type. B(Of MySpark) derives from A(Of MySpark) which implements the IMagic(Of MySpark) interface which itself has no base type. They don't share any base type in common, nor even any interface. Hence you cannot assign one instance to another. B(Of MySpark) does not derive from A(Of ISpark).

    To dive further into this topic I recommend you read about covariance and contravariance. It is applicable when working with generic interfaces (but not classes) and when you want to support mixing type parameters that may be base and derived types. There are restrictions on what you can do but the interface itself must identify the co-/contra-variance.

    In your specific case you're dealing with the base/derived classes so variance won't help here. However you can switch over to using the interfaces and things start working again.

    Dim MyB As IMagic(Of ISpark) = New B(Of MySpark)
    

    Think of classes as the implementation of an interface and only use them when you need a specific instance (generally when creating them). The remainder of the time use the interface and, assuming the interface variance is correct, things will work as expected.

    2 people found this answer helpful.

0 additional answers

Sort by: Most helpful