Type generated from string class name not recognized in newing of the same type

I have some vb.net code that takes a string version of a class name, finds the type in the assemblies and uses that type to create an instance of a generic list of that type using CreateInstance. The code is below at the very bottom. My problem is that I want to make this totally generic so it will work with any type that is passed in as a string name of the type.

The created generic type Ty has the same type as One.Two.Three.MyClass (without quotes around it) if I use gettype with both Ty and One.Two.Three.MyClass in the watch window so it seems they are exactly the same. However when I try to use type Ty to new a new instance of the type, the compiler tells me Type Ty is not defined. If I replace Ty with One.Two.Three.MyClass (no quotes around it) the compiler accepts it as follows and the code runs fine; the use of Ty is the problem in the code at the very bottom:

  list.Add(New ALLMEDS.EMR.Report.MUListData(lxRow("FirstName"), lxRow("LastName"), lxRow("ChartNumber"), lxRow("DOB"), lxRow("Reason")))

Here is the complete code below that is giving me a problem. The use of Ty in the first two lines compiles and runs fine; it is only in the "newing" of the class that it causes trouble.

 Dim Ty As Type = FindType("One.Two.Three.MyClass")
    Dim list As IList = CType(Activator.CreateInstance(GetType(List(Of )).MakeGenericType(Ty)), IList)



    If lxDS.Tables.Count > 0 Then
            For Each lxRow As DataRow In lxDS.Tables(0).Rows
            (THE LINE BELOW CAUSES THE COMPILE ERROR:Type Ty is not defined)
list.Add(New Ty(lxRow("FirstName"), lxRow("LastName"), lxRow("ChartNumber"), lxRow("DOB"), lxRow("Reason")))
            Next
    End If

    evtShowReport(lxParameter, list)
Jon Skeet
people
quotationmark

The problem is that you're treating the token Ty as if it were the name of a type. It's not - it's the name of a variable. The type of that variable is Type, but it's still a variable. Variables and type names are entirely different things, and you can't treat them as if they were the same thing.

You've already taken account of that in your second line of code - if you'd tried to write:

Dim list as IList = new List(Of Ty)

that would have the same kind of error - because generic type arguments have to be names of types (or type parameters).

Likewise, when you try to call a constructor with New, you have to specify the name of a type (or a type parameter constrained to have a parameterless constructor). Aside from anything else, that's how the compiler can check that the constructor you're trying to call exists - because it knows which type you're talking about at compile time.

If you only have a variable whose value is a Type reference, the compiler can't check anything - so you have to use reflection. You could either call Type.GetConstructor (or TypeInfo.GetConstructor in the modern reflection API), or call Activator.CreateInstance and let it figure out the appropriate constructor at execution time. So for example, you could use:

list.Add(Activator.CreateInstance(Ty, lxRow("FirstName"), lxRow("LastName"), lxRow("ChartNumber"), lxRow("DOB"), lxRow("Reason")))

people

See more on this question at Stackoverflow