2

I need to fetch a C# type by name, where the interface should be pretty much identical to typeof except that the string is named at runtime instead of the type being named at compilation time- i.e. typeof(x) == runtime_typeof("x") for all x. Fairly critically, I also need to deal with various generic situations like generic definitions and generic types.

I've seen some other solutions in C# for getting type by name but they all seem to involve CLR mangled names rather than C# source names.

Furthermore, I need to retrieve a source name for a given Type object that should be of the same form.

How can I look up types by C# source name and retrieve a C# source name from a type?

Edit: Assembly qualified names and C# source names are not the same thing. Hence the explicitness in the question.

What I'm really looking for is that the names should be identical to the names you would use to reference them from C# source code- so IEnumerable<T> or IEnumerable<>, rather than IEnumerable[1]` or whatever. Requiring the full namespace is fine for me and I already know what assemblies to look in, so it's mostly an issue of what happens when generics and name mangling are involved.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • `Assembly.GetType` or `Type.GetType` ? Btw it looks like the XY Problem. What are you trying to achieve, maybe there is a better solution? – Sriram Sakthivel Apr 21 '15 at 13:39
  • Be aware that `GetType` needs a _fully qualified name_. e.g. `Type.GetType("string")` will return `null`. – D Stanley Apr 21 '15 at 13:40
  • This question isn't a duplicate because like I stated, I need to handle particularly *generic* types in a particular way which that answer and question doesn't. – Puppy Apr 21 '15 at 13:56
  • 1
    I'm not sure I understand your requirement. Sorry for that. But for generic types, you need to use the back tick, generic parameter count, and [type names]. For example `Type t = Type.GetType("System.Collections.Generic.List`1[System.Int32]"); Type t2 = Type.GetType("System.Collections.Generic.Dictionary`2[System.Int32,System.String]");` – Sriram Sakthivel Apr 21 '15 at 14:02
  • 1
    Perhaps this question would be more clear if you gave an example? What is a *source name* exactly? If the duplicate doesn't answer your question, I'm not clear what your question is. – Liam Apr 21 '15 at 14:39
  • 1
    @Liam: The name you would use if you were just referencing it from C# source code. – Puppy Apr 21 '15 at 15:10
  • So you mean the class name? But you could have multiple classes with the same name in different namespaces? This works in c# because of the using statements. That's why you need the fully qualified name. – Liam Apr 21 '15 at 16:25
  • Apologies for misunderstanding the original question. Updated my answer with something that should match your specs (assuming that the namespace and assembly of the desired type are known). Let me know if it still won't work for you. – LiamK Apr 21 '15 at 20:53
  • 1
    Fully qualifying the name by namespace is fine by me. But there's a difference between the qualified name and assembly qualified name, and especially when it comes to generics. – Puppy Apr 21 '15 at 21:41

1 Answers1

4
  • Retrieving a type name by string source code representation

After much deliberation, I think I finally found something that addresses your core problem. If all you really need is a typeof() function that can take a string parameter, then you can use the CSharpCompilerServices to make it so:

 // set the assembly location, namespace, and string name of desired type
 var assemblyLocation = Assembly.GetExecutingAssembly().Location;
 var namespaceToType = "Namespace.Of.Type";
 var desiredType = "C<int>";

 // write some code using above parameters
 var template = "using {0};\nusing System;\npublic class Snippet {{\n\tpublic static Type main() {{\n\t\treturn typeof({1});\n\t}}\n}}";

 var code = string.Format(template, namespaceToType, desiredType);

 // compile code in memory, then return value via reflection
 var provider = CodeDomProvider.CreateProvider("CSharp");
 var parameters = new CompilerParameters();
 parameters.GenerateExecutable = false;
 parameters.GenerateInMemory = true;
 parameters.ReferencedAssemblies.Add(assemblyLocation);
 var results = provider.CompileAssemblyFromSource(parameters, code);
 return mytype = results.CompiledAssembly.GetType("Snippet").GetMethod("main").Invoke(null, null) as Type;

I can't speak to the performance of this solution, but from the comments it sounds like you're using this in a build process so (hopefully) that won't matter too much.

I left my old answers in for posterity since I recieved some upvotes on them:

Per the MSDN article here:

If the type is in the currently executing assembly or in Mscorlib.dll, it is sufficient to supply the type name qualified by its namespace

  • Retrieving a type by Namespace Qualified Name (partial match)

    Assembly.GetExecutingAssembly()
            .DefinedTypes.Where(type => type.Name.Contains("MyType")).First();
    
LiamK
  • 795
  • 6
  • 16