Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading a generic type by name when the generics arguments come from multiple assemblies

I need to create a type from its full name only Ex: "System.String" or "Tuple'2[string,Mytype]". there is no information about the assembly in the string. Here is what the code look like.

private static Type LoadType(string typeName)
{
    // try loading the type
    Type type = Type.GetType(typeName, false);

    if (type != null)
        return type;

    // if the loading was not successfull iterate all the referenced assemblies and try to load the type.
    Assembly asm = Assembly.GetEntryAssembly();
    AssemblyName[] referencedAssemblies = asm.GetReferencedAssemblies();
    foreach (AssemblyName referencedAssemblyName in referencedAssemblies)
    {
        type = referencedAssembly.GetType(typeName, false);
        if (type != null)
            return type;
    }
    throw new TypeLoadException(string.Format("Could not load the Type '{0}'",typeName));
}

this method works when the type is not generic. But for generic types iterating through the assemblies always fails because no assemblies contains all the definitions required to build the type.

Is there a way to provide multiples assemblies for type resolution when calling GetTypes ?

like image 220
Cheick Avatar asked Feb 16 '10 21:02

Cheick


People also ask

Can a generic class have multiple constraints?

Multiple interface constraints can be specified. The constraining interface can also be generic.

Can you instantiate a generic type?

Cannot Instantiate Generic Types with Primitive Types. Cannot Create Instances of Type Parameters. Cannot Declare Static Fields Whose Types are Type Parameters. Cannot Use Casts or instanceof With Parameterized Types.

What is generic type arguments?

The generic argument list is a comma-separated list of type arguments. A type argument is the name of an actual concrete type that replaces a corresponding type parameter in the generic parameter clause of a generic type. The result is a specialized version of that generic type.

What is generic type constraint?

A type constraint on a generic type parameter indicates a requirement that a type must fulfill in order to be accepted as a type argument for that type parameter. (For example, it might have to be a given class type or a subtype of that class type, or it might have to implement a given interface.)


3 Answers

You're going to have to do it the hard way I think. Fortunately it's not that hard. Pretty straightforward:

  • Parse the type name into the type definition and the generic type arguments.
  • Obtain the generic type definition object
  • Obtain the type objects for each generic type argument
  • Construct the generic type out of the generic type definition and the generic type arguments using the MakeGenericType method on the type definition object.
like image 97
Eric Lippert Avatar answered Oct 27 '22 01:10

Eric Lippert


Something like this....

Type.GetType("namespace.typename`1[[namespace.typename, assemblyname]], assemblyname");

e.g.

var type = Type.GetType("System.Collections.Generic.List`1[[System.String, mscorlib]], mscorlib");
var instance = Activator.CreateInstance(type);

or, as Eric says.. if you have the types in hand, just build it..

Type genericType = typeof(Dictionary<,>);
Type constructedType = genericType.MakeGenericType(new Type[] { typeof(String), typeof(String) });
like image 40
Sky Sanders Avatar answered Oct 26 '22 23:10

Sky Sanders


If the format is ´t1[[t2, a2][t3, a3]], a1´, this works:

private Type GetAckwardType(string typeName)
{
    var tokens = typeName.Split(new []  {"[[", "]]", "]["}, StringSplitOptions.None);
    if (tokens.Length == 1)
        return Type.GetType(typeName, true);

    var plainType = Type.GetType(tokens[0] + tokens[tokens.Length - 1], true);
    var args = tokens.Skip(1).Take(tokens.Length - 2).Select(_ => Type.GetType(_, true)).ToArray();
    return plainType.MakeGenericType(args);
}
like image 41
Lars Corneliussen Avatar answered Oct 27 '22 01:10

Lars Corneliussen