views:

51

answers:

3

Hi

I'm trying to create an object Of a specific type. I've got the following code, but it fails because it can't cast the new table object to the one that is already defined. I need table to start of an IEnumerable type so I can't declare is an object.

Public sub getTable(ByVal t as Type)

   Dim table As Table(Of Object)

   Dim tableType As Type = GetType(Table(Of )).MakeGenericType(t)

   table = FormatterServices.GetUninitializedObject(tableType)

End sub 

So in short - is there a way of changing a variable type at runtime? (or a better way of doing what I'm doing)

Thanks in advance.

James

A: 

Look at these for a couple of examples of what I think you are asking:

JB King
+1  A: 

Try making the entire method generic (and use a function rather than a sub, too):

Public Function GetTable(Of T)() As Table(Of T)
Joel Coehoorn
A: 

Before answering, I do have two remarks:

  • I agree with Joel that a generic solution would be much simpler, but without more context I'll assume you really do need reflection
  • why do you use FormatterServices.GetUninitializedObject()? This will not call the constructor of your Table object. I'm guessing you actually mean to use Activator.CreateInstance() here.

Now, over to the issue at hand. You have run into the lack of support for co- (and contra-)variance in .Net. The assignment statement will never work, also without reflection:

' does not compile (with Option Strict On)
Dim t as Table(Of Object) = New Table(Of Product)

The reason is that the types are actually different. Although Product inherits from Object, that does not imply that Table(Of Product) does not inherit from Table(Of Object).

.Net 4 actually does have support for generic covariance, but only for generic interfaces and delegate types. By annotating a generic type with the 'out' keyword, you can mark it as generically covariant. For example, the IEnumerable generic interface declaration looks like this:

 IEnumerable(Of Out T)

This means that it's now possible to do the following:

 Dim mylist As IEnumerable(Of Object) = new List<Product>()

So one can safely assign a list which is IEnumerable(Of Product) to a variable of type IEnumerable(Of Object).

Here's an explanation of co- and contravariance in VB.Net

So, what you could do is define an interface for the generic table:

Interface ITable(Of Out T)
End Interface

Then you can implement this interface in your generic Table class:

Class Table(Of T)
    Implements ITable(Of T)
End Class

Then this will work:

Function CreateTable(ByVal t As Type) As ITable(Of Object)
    Dim result As ITable(Of Object) 
    Dim type = GetType(Table(Of )).MakeGenericType(t)
    result = FormatterServices.GetUninitializedObject(type)
    Return result
End Function

Of course, even better would be to use IEnumerable(Of T) instead of ITable(Of T), if possible.

jeroenh