ITypeResolutionService for constructed / generic .net types

If you are writing your own customized form designer, one of the services you need to provide is ITypeResolutionService.
Given a name of type, this service is responsible for returning corresponding "System.Type".

A "Type" can be one of following :

1. default type (defined in one of the standard .net assemblies e.g. mscorlib.dll or system.dll etc provided by .net framework)
"System.Type" for such types can be retrieved using Type.GetType() API.
2 custom type defined in user / 3rd party assemblies:
For such types, you need to know the assembly name in which this type is defined.
First you have to load the Assembly and then look up for that type name in loaded assembly as below:

Assembly asm = Assembly.Load("referenced assembly name");
asm.GetType(strTypename);


Now let's see how .net generic types are represented.
Let's say we create a generic class ABC < T,U > in "XYZ" assembly.
Internal representation for ABC class would be ABC`2
(i.e. classname followed by backtick followed by number of generic type parameters).

To constuct an object of this class we have to provide 2 types such as
ABC < string,int > obj;
Here type of obj is a constructed type and is internally represented as "ABC`2[string,int]".

Now if you try to load Type for "ABC`2[string,int]" from XYZ assembly, it returns null because assembly knows about generic type "ABC`2". It doesn't know about its constructed types.
So to return System.Type for such constructed types, you need to first get its generic type from assembly and then on that type call Type.MakeGenericType() passing a Type array(Type[ ]) for its type arguments.

Here is a sample implementation of ITypeResolutionService:


Using System;

MyTypeResolutionService : ITypeResolutionService
{
public Type GetType(String name)
{
Type t = Type.GetType(name);
if(t == null)
{
// type is defined in some assembly.
//name must include name of assembly.

String assemblyName = GetAsmName(name);//helper method
if(String.IsNullOrEmpty(assemblyName))
return null;

String typeName = GetTypeName(name); //helper method

// check if this is a consturected type
String typeArgs;
bool isConstructed = false;
// look for backtick.
// if present means a generic type
int pos = name.IndexOf('`');
if(pos != -1)
{
// look for square bracket.
// if present means a constructed type.
pos = name.IndexOf('[',pos);
if(pos != -1){
isConstructed = true;
// get "abc'2" from "abc`2[string,int]"
String genericTypeName = typeName.SubString(0,pos);
// get "string,int" from "abc`2[string,int]"
typeArgs=
typeName.SubString(pos+1,typeName.Length - 1);

typeName = genericTypeName;
}
}


Assembly asm = Assembly.Load(assemblyName);
t = asm.GetType(typeName);

if( t != null && isConstructed)
{
Type[] types = getArgTypes(typeArgs);
//TODO: if types is null, return null
return t.MakeGenericType(types); .
}
}

return t;
} // end of GetType()

// here comma separated typeArgs passed is likely to contain
// again some other constructed types
// In such case GetType() is called recursively for all nested
// constructed typeArgs ..
private Type[] getArgTypes(String name)
{
// first split type argument names;
List < String > argList = new ArrayList < String > ();
int brackets;
int argStartpos = 0;
for(i =0;i < name.Length;i++)
{
if(name[i] == '[')
brackets++;
else if(name[i] == ']')
brackets--;
else if(name[i] == ',' && brackets == 0)
{
argList.Add(name.SubString(argStartpos,i));
// point to start of next type argument
argStartpos = i+1; .
}
}
// add the last type arg
argList.Add(name.SubString(argStartpos);

//now call GetType() for each typeArg in argList
Type[] retTypes = new Type[argList.Count];
for(int i=0;i < argList.Count;i++)
retTypes[i] = GetType(argList[i]);

return retTypes;
} // end of getTypeArgs()
} // end of MyTypeResolutionService