82

I have MyClass<T>.

And then I have this string s = "MyClass<AnotherClass>";. How can I get Type from the string s?

One way (ugly) is to parse out the "<" and ">" and do:

Type acType = Type.GetType("AnotherClass");  
Type whatIwant = typeof (MyClass<>).MakeGenericType(acType);

But is there a cleaner way to get the final type without any parsing, etc.?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
DeeStackOverflow
  • 2,741
  • 4
  • 23
  • 23

5 Answers5

100

The format for generics is the name, a ` character, the number of type parameters, followed by a comma-delimited list of the types in brackets:

Type.GetType("System.Collections.Generic.IEnumerable`1[System.String]");

I'm not sure there's an easy way to convert from the C# syntax for generics to the kind of string the CLR wants. I started writing a quick regex to parse it out like you mentioned in the question, but realized that unless you give up the ability to have nested generics as type parameters the parsing will get very complicated.

Neil Williams
  • 12,318
  • 4
  • 43
  • 40
  • +1 - great answer, thanks! I was fiddling around trying to find out how to handle generics! – marc_s Apr 06 '09 at 15:39
  • Thanks. This works and I have to modify the code to format the string this way. However, was wondering if there is still a way to simply use : "MyClass" exactly the way it is shown in the string to get the Type instance. Looks a lot cleaner. – DeeStackOverflow Apr 06 '09 at 16:32
  • You dont have to modify the code to format the string in this way, just call ToString() on the Type. – Rush Frisby Jun 10 '14 at 19:17
  • If the type is a custom class in a different assembly (not a type like string), how would you specify it? I tried giving the fully qualified assembly name inside [], but that didn't work. – Ε Г И І И О Jun 24 '21 at 08:07
38

Check out Activator.CreateInstance - you can call it with a type

Activator.CreateInstance(typeof(MyType))

or with an assembly and type name as string

Activator.CreateInstance("myAssembly", "myType")

This will give you an instance of the type you need.

If you need the Type rather than the instance, use the Type.GetType() method and the fully qualified name of the type you're interested in, e.g.:

string s = "System.Text.StringBuilder";
Type myClassType = Type.GetType(s);

That'll give you the Type in question.

mipe34
  • 5,596
  • 3
  • 26
  • 38
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 3
    This just gets an instance of the type, not a System.Type instance, which based on the code snippet, seems to be what OP is looking for. – Daniel Schaffer Apr 06 '09 at 15:26
26

I've needed something like this and I ended up writing some code to parse the simple type names I needed. Of course there is room for improvement, as it will not identify generic type names like List<string>, but it does just fine for string, int[], decimal? and such. Sharing in case this helps anyone.

public static class TypeExtensions
{
  public static Type GetTypeFromSimpleName(string typeName)
  {
    if (typeName == null)
      throw new ArgumentNullException("typeName");

    bool isArray = false, isNullable = false;

    if (typeName.IndexOf("[]") != -1)
    {
      isArray = true;
      typeName = typeName.Remove(typeName.IndexOf("[]"), 2);
    }

    if (typeName.IndexOf("?") != -1)
    {
      isNullable = true;
      typeName = typeName.Remove(typeName.IndexOf("?"), 1);
    }

    typeName = typeName.ToLower();

    string parsedTypeName = null;
    switch (typeName)
    {
      case "bool":
      case "boolean":
        parsedTypeName = "System.Boolean";
        break;
      case "byte":
        parsedTypeName = "System.Byte";
        break;
      case "char":
        parsedTypeName = "System.Char";
        break;
      case "datetime":
        parsedTypeName = "System.DateTime";
        break;
      case "datetimeoffset":
        parsedTypeName = "System.DateTimeOffset";
        break;
      case "decimal":
        parsedTypeName = "System.Decimal";
        break;
      case "double":
        parsedTypeName = "System.Double";
        break;
      case "float":
        parsedTypeName = "System.Single";
        break;
      case "int16":
      case "short":
        parsedTypeName = "System.Int16";
        break;
      case "int32":
      case "int":
        parsedTypeName = "System.Int32";
        break;
      case "int64":
      case "long":
        parsedTypeName = "System.Int64";
        break;
      case "object":
        parsedTypeName = "System.Object";
        break;
      case "sbyte":
        parsedTypeName = "System.SByte";
        break;
      case "string":
        parsedTypeName = "System.String";
        break;
      case "timespan":
        parsedTypeName = "System.TimeSpan";
        break;
      case "uint16":
      case "ushort":
        parsedTypeName = "System.UInt16";
        break;
      case "uint32":
      case "uint":
        parsedTypeName = "System.UInt32";
        break;
      case "uint64":
      case "ulong":
        parsedTypeName = "System.UInt64";
        break;
    }

    if (parsedTypeName != null)
    {
      if (isArray)
        parsedTypeName = parsedTypeName + "[]";

      if (isNullable)
        parsedTypeName = String.Concat("System.Nullable`1[", parsedTypeName, "]");
    }
    else
      parsedTypeName = typeName;

    // Expected to throw an exception in case the type has not been recognized.
    return Type.GetType(parsedTypeName);
  }
}

Using it is as simple as writing this:

Type t;

t = TypeExtensions.GetTypeFromSimpleName("string");
t = TypeExtensions.GetTypeFromSimpleName("int[]");
t = TypeExtensions.GetTypeFromSimpleName("decimal?");
Phillippe Santana
  • 2,906
  • 2
  • 28
  • 29
3

To just get the type object from the string, use:

Type mytype = Type.GetType(typeName);

You can then pass this to Activator.CreateInstance():

Activator.CreateInstance(mytype);
Turnor
  • 1,836
  • 12
  • 14
0

I don't have much time to parse through this, though I think I have seen some similar answers. In particular, I think they are doing exactly what you want to do here:

Entity Framework Generic Repository Error

(String.Format("[{0}]", baseType.Name.ToString())).OfType<T>();

Hopefully this helps, let me know more specifically if this isn't.

Community
  • 1
  • 1
Jeff Ancel
  • 3,076
  • 3
  • 32
  • 39