DeeStackOverflow
DeeStackOverflow

Reputation: 2781

How can I get generic Type from a string representation?

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

Upvotes: 83

Views: 94348

Answers (5)

marc_s
marc_s

Reputation: 754488

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.

Upvotes: 38

Phillippe Santana
Phillippe Santana

Reputation: 3116

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

Upvotes: 26

Neil Williams
Neil Williams

Reputation: 12578

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.

Upvotes: 101

Turnor
Turnor

Reputation: 1856

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

Upvotes: 3

Jeff Ancel
Jeff Ancel

Reputation: 3091

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.

Upvotes: 0

Related Questions