How can I get generic Type from a string representation?

C#ReflectionTypes

C# Problem Overview


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.?

C# Solutions


Solution 1 - C#

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.

Solution 2 - C#

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.

Solution 3 - C#

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?");

Solution 4 - C#

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);

Solution 5 - C#

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:

https://stackoverflow.com/questions/695878/entity-framework-generic-repository-error/698365

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

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDeeStackOverflowView Question on Stackoverflow
Solution 1 - C#Neil WilliamsView Answer on Stackoverflow
Solution 2 - C#marc_sView Answer on Stackoverflow
Solution 3 - C#Phillippe SantanaView Answer on Stackoverflow
Solution 4 - C#TurnorView Answer on Stackoverflow
Solution 5 - C#Jeff AncelView Answer on Stackoverflow