3

Take this scenario:

Public Interface IMyClass
End Interface

Public mustinherit class MyBaseClass : implements IMyClass
End Class

public class MyClass : inherits MyBaseClass
End Class

public class MyModel(of t as IMyClass)

    private Dim _parameter as t

    Public Sub New(byval parameter As t)
        _parameter As t
    End Sub
End class

In my controller, I can do this with no problem:

Dim _myclass as IMyClass = new MyClass()

Can I do something similar with this:

Dim _myModel as MyModel(of IMyClass) = new MyModel(of MyClass)

???

My initial thought was wrong, as I thought the conversion could be done automatically, but it appears it is not done. Any way to achieve the same thing within .NET?

EDIT I updated the MyModel class to show more of what I was doing. I want to constrain the instance I create, but then do what would be a narrowing conversion with traditional, non-generics code. Basically, my partial Razor views would require the explicit model, and those views end up rendering another view that will take that model and display it. Because the models all implement or inherit a class that implements IMyClass, all the methods should exist on all of the instances and should be callable but the types are not interchangable.

ps2goat
  • 8,067
  • 1
  • 35
  • 68
  • this applies to c#, but this will apply to your case. http://stackoverflow.com/questions/1078423/c-sharp-is-variance-covariance-contravariance-another-word-for-polymorphis – Daniel A. White Mar 08 '13 at 02:46
  • That refers to a list, not to a single instance. – ps2goat Mar 08 '13 at 15:43
  • Edited what I'm trying to do. @DanielA.White, if you could give me an example as to how this would apply in this case, I'd appreciated it. The use case of a List(of T) makes sense, but I'm not 100% sure how to apply it in this situation. – ps2goat Mar 08 '13 at 15:53
  • @ps2goat The other answer merely uses `List` as another generic type but the explanation isn’t specific to `List`, it applies to your case. – Konrad Rudolph Mar 08 '13 at 15:55

2 Answers2

1

Let’s modify MyModel slightly, shall we?

Public Class MyModel(Of T As IMyClass)
    Private _parameter As T

    Public Sub Something(parameter As T)
        _parameter = parameter
    End Sub
End class

Public Class MyClassA : Inherits MyBaseClass
End Class

Public Class MyClassB : Inherits MyBaseClass
End Class

Dim _myModel As MyModel(Of IMyClass) = New MyModel(Of MyClassA)()
_myModel.Something(New MyClassB()) ' Boom!

If the assignment were allowed the last line would pose a problem: MyMode(Of MyClassA)._parameter has type MyClassA but the last line would assign an object of the (unrelated) type MyClassB. This is illegal and so VB forbids it.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
0

Do you need multiple varieties of MyModel, or are you just attempting to require that the stored object be constrained to IMyClass?

Simplest approach (that might not do everything you need):

Public Interface IMyClass
    Sub DoIt()
End Interface

Public Class MyModel
    Private ReadOnly _parameter As IMyClass
    Public Sub New(parameter As IMyClass)
        _parameter = parameter
    End Sub
    Public Sub DoItToIt()
        _parameter.DoIt()
    End Sub
End Class

Public Class MyClassA
    Implements IMyClass
    Public Sub DoIt() Implements IMyClass.DoIt
    End Sub
End Class

Public Class Tests
    Public Sub Main()
        Dim model1 As MyModel = New MyModel(New MyClassA)
        model1.DoItToIt()
    End Sub
End Class

Next step up in complexity is to define an interface IHasMyClass for classes that contain an IMyClass. This supports manipulations based on the allowed type, and the actual type, of the contained object:

Public Interface IMyClass
    Sub DoIt()
End Interface

Public Interface IHasMyClass
    Function GetIt() As IMyClass
    Function GetItsType() As Type
    Function GetAllowedType() As Type
End Interface

Public Class MyModel(Of T As IMyClass)
    Implements IHasMyClass

    Private ReadOnly _parameter As IMyClass
    Public Sub New(parameter As IMyClass)
        _parameter = parameter
    End Sub
    Public Sub DoItToIt()
        _parameter.DoIt()
    End Sub

    Public Function GetItAsT() As T
        Return _parameter
    End Function

    Public Function GetIt() As IMyClass Implements IHasMyClass.GetIt
        Return _parameter
    End Function

    Public Function GetItsType() As Type Implements IHasMyClass.GetItsType
        Return _parameter.GetType()
    End Function

    Public Function GetAllowedType() As Type Implements IHasMyClass.GetAllowedType
        Return GetType(T)
    End Function
End Class

Public Class MyClassA
    Implements IMyClass
    Public Sub DoIt() Implements IMyClass.DoIt
    End Sub
End Class

Public Class Tests
    Public Sub Main()
        ' Allow any IMyClass
        Dim model1 As MyModel(Of IMyClass) = New MyModel(Of IMyClass)(New MyClassA)
        model1.DoItToIt()
        Dim it As IMyClass = model1.GetIt()
        Dim allowedT As Type = model1.GetAllowedType()

        ' Restrict to MyClassA
        Dim modelA As MyModel(Of MyClassA) = New MyModel(Of MyClassA)(New MyClassA)
        modelA.DoItToIt()
        Dim itA1 As IMyClass = modelA.GetIt()
        Dim itA2 As MyClassA = modelA.GetItAsT()
        Dim allowedTA As Type = modelA.GetAllowedType()
    End Sub
End Class

In Tests(), notice that we now need to declare whether we are creating a MyModel that accepts ANY IMyClass MyModel(Of IMyClass), or one that requires a specific sub-class MyModel(Of MyClassA).

If we want to manipulate MyModels, that may be either of the above types, we use the common interface:

Dim model As IHasMyClass
model = model1
...
model = modelA

Or in your case, to support all the functionality of MyModel, rename IHasMyClass as IMyModel, and add the various MyModel functions, but instead of T, use IMyClass:

Public Interface IMyModel
    Function GetIt() As IMyClass
    Function GetItsType() As Type
    Function GetAllowedType() As Type

    Sub DoItToIt()
    Function CompareIt(other As IMyClass) As Integer
End Interface

And make appropriate changes/additions to IMyClass and MyModel.

Then it becomes possible to do:

Dim model As IMyModel = modelA
If model.CompareIt(model1.GetIt()) > 0 ...
ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196