C# Getting Type out of a string variable and using it in generic method
Asked Answered
B

3

1

I want to be able to get the actual Type of a string value I receive by some means (i.e from database) so I can use that Type in generic method like DoSomething<Type>().

In my project, I have classes Plane, and Car located in MyCompany.MySolution.Vehicle namespace like so

- MyCompany.MySolution.Vehicle
  |+Interfaces
  |-Implementations
    |-Car
    |-Plane

I receive type of the vehicle as a string. So, I get string "Car" which means, I need to get Type Car so I can use that type in a generic method to register it like so:

MyFactory.Register<Car>(carId)

So, MyFactory is static class calling Register() method.

Similarly, I receive string "Plane" which means, I need to get Type Plane so I can use that type in the generic method above to register a Plane.

I tried using something like

MyFactory.Register<Type.GetType("MyCompany.MySolution.Vehicle.Implementations.Car")>(carId)

,but that does not work.

Barner answered 13/2, 2019 at 20:51 Comment(3)
Have you tried using the fully-qualified name of Car (including the namespace)? i.e. Type.GetType("MyCompany.MySolution.Vehicle.Implementations.Car")Fanchon
Possible duplicate of Using System.Type to call a generic methodOmit
@Omit No, it is not duplicate. Rufus, yes I tried that, that wont return anythingBarner
E
3

If you want to invoke a Generic Method with a Type parameter generate at Runtime, you could do something like this:

var vehicleString = "Car";

// use the fully-qualified name of the type here
// (assuming Car is in the same assembly as this code, 
//  if not add a ", TargetAssemblyName" to the end of the string)
var vehicleType = 
    Type.GetType($"MyCompany.MySolution.Vehicle.Implementations.{vehicleString}");

// assuming MyFactory is the name of the class 
// containing the Register<T>-Method
typeof(MyFactory).GetMethod("Register")
    .MakeGenericMethod(vehicleType)
    .Invoke(this);

Working Example

Just as a note:

This is not how generics are supposed to be used. I'm just pointing out the possibility, not giving you an ideal answer to the problem you're proposing. Maybe you should rethink some of your architectural design choices!

Ecclesiasticism answered 13/2, 2019 at 20:59 Comment(2)
I dont need to GetMethod from MyFactory. It is a static class so I can use it just like I explained MyFactory.Register<Car>(carId). The problem is as I explained how to get the type Car out of string "Car" so I can put that type in Register<Type>. Putting your Register<vehicleType> errors with "vehicleType is a variable but it is used as a type" error. That is exactly what I explained I was trying to do minus your attempt to use GetMethod.Barner
Yes you do. You can't pass a type variable as a generic parameter without using Reflection. I just added a working example to my Answer.Ecclesiasticism
S
2

If Register<T> does something like this

void Register<T>(int id)
{
    _dictionary.Add(typeof(T), ...);
}

Create a non generic overload

void Register(Type t, int id)
{
    _dictionary.Add(t, ...);
}

This new overload is not type safe, but creating a type out of a string isn't anyway.

The purpose of generics is to gain variability (not to be confused with dynamic behavior!) while keeping type safety. But when types are determined at runtime, type safety is not given and generics are more of a hindrance than useful.

Note that type safety is ensured by the compiler, which does of course not work at runtime.

Skardol answered 13/2, 2019 at 21:0 Comment(5)
So, how do I get the Type t out of string "Car" so I can pass it into Register(Type t, int id)? As explained, I dont know the Type, I have string value "Car" out of which I have to get Type Car :)Barner
Use Type.GetType. First look into typeof(Car).FullName to see the exact name you must supply.Skardol
no, you cannot use Type.GetType("") inside a generic method. You cannot do DoSomething<Type.GetType("")>(Id), that wont workBarner
Of course not as generic type parameter, but you can do it to get a Type object for my second method. (This is why I suggested it).Skardol
Thanks but I need to use it as generic param, tying to figure that out but your suggestion is certainly helpful, thanksBarner
C
0

You can use a dictionary which holds all your types with strings keys:

var d = new Dictionary<String,Type>(); 
d.Add("Car",typeof(Car)); 
d.Add("Plane",typeof(Plane)); 

Then if you get the string "Car" from the database you can get the type like this:

var myType = d["Car"]; 

Then use myType as the real Type.

Cedeno answered 13/2, 2019 at 21:14 Comment(1)
Well, my register method is trying to add it to dictionary just as you explain. But as explained, my Register method is generic, so need to know the type to be able to call it like Register<Car>(carId)Barner

© 2022 - 2024 — McMap. All rights reserved.