tags:

views:

109

answers:

5

the following generic method gives the compile error "Error 13 Value of type 'Distribution' cannot be converted to 't'" :

Public Shared Function CreateObject(Of t)(ByVal ID As Integer) As t

        Dim TType As Type = GetType(t)

        If TType Is GetType(Distribution) Then
            Return CreateDistribution(ID)

        ElseIf TType Is GetType(Accrual) Then
            Return CreateAccrual(ID)

        End If


    End Function

CreateDistribution returns an object of type 'Distribution'. I'm trying to get the method to perform an action based on the type of t supplied and then return an object of type t. What am I doing wrong?

** Edit: I've commented out the entirety of Distribution other than the class declaration and still get the same error.

+2  A: 

The compiler can't know ahead of time that the return type of CreateDistribution will match the type t, regardless of your if statement. Does changing the line to this work?

Return CType(CreateDistribution(ID), t)

Same for the second obviously.

David M
I had this in place originally but got the same error...
Simon
How about DirectCast rather than CType?
David M
Nope, same error!
Simon
+1  A: 

Generic methods are resolved at compile-time, so the compiler needs to know up front what type T it is going to compile the function with. Looks like you're looking to do a return based on runtime checking, in which case rather than a generic you'll want a method that returns an object that all of your possible returns inherit from. The most basic one you could use would be object -- but obviously wherever you call it from you'd have to do some type checking.

David Hay
+2  A: 

You need to upcast to the return values to Object, then downcast to t.

For example:

Return CType(CType(CreateDistribution(ID), Object), t)

The two casts are necessary because the compiler doesn't know that t is Distribution. Therefore, it cannot allow you to cast from Distribution to t (which, as far as the compiler is concerned, might be Integer). However, once you upcast to Object, the second cast is fine, because Object can by definition be converted to t, no matter what type t is.
Pre-emptive snarky comment: Yes, I'm aware that that isn't true for pointers.

SLaks
Bingo, this now compiles. I never would have thought of that...
Simon
This will work and does preserve the generic function, but you better make sure that the object you're planning on returning really is of type t before making the casts.
David Hay
@David:Obviously. That's why he has the `If` statements.
SLaks
A: 

I think you're always going to get an error, as at least one of your return statements will have a type mismatch. The compiler is almost certainly not smart enough to work out that only one of them can possibly be executed for a given t

Andrew Aylett
Not true! See @SLaks answer.
Simon
A: 

Here is a more generic way to accomplish what you are trying to do:

    Public Function CreateInstance(Of T)(ByVal ParamArray args() As Object) As T
        Dim obj As T

        If args IsNot Nothing AndAlso args.Length > 0 Then
            obj = CType(Activator.CreateInstance(GetType(T), args), T)
        Else
            obj = Activator.CreateInstance(Of T)()
        End If

        Return obj
    End Function
TGnat
Interesting, but what controls the parameters you pass in ParamArray? Presumably it would be really easy to pass in the wrong parameters (types, qty or value) as there would be no compile time validation of this.
Simon