2010-02-16 9 views
6

Necesito crear un tipo solo a partir de su nombre completo Ej: "System.String" o "Tuple'2 [string, Mytype]". no hay información sobre el ensamblado en la cadena. Aquí se muestra el código.Cargando un tipo genérico por nombre cuando los argumentos genéricos provienen de ensamblados múltiples

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

este método funciona cuando el tipo no es genérico. Pero para los tipos genéricos, la iteración a través de los ensamblados siempre falla porque ningún ensamblaje contiene todas las definiciones necesarias para construir el tipo.

¿Hay alguna forma de proporcionar conjuntos múltiples para la resolución de tipo al llamar a GetTypes?

+0

si está ejecutando programáticamente los nombres de tipos y modificando el nombre del tipo genérico que se creará, para una lista , por ejemplo, asegúrese de usar AssemblyQualifiedName. –

+1

¿Qué vas a hacer con el caso donde hay dos tipos en dos referencias diferentes que tienen exactamente el mismo nombre? –

+0

todos los tipos tienen un prefijo con su espacio de nombres, así que con suerte esto no sucederá a menudo, la posterior deserialización fallará. Puedo retroceder y probar otro tipo en otro ensamblaje y volver a intentar la deserialización. Pero sé que es más fácil decirlo que hacerlo. –

Respuesta

7

vas a tener que hacerlo de la manera difícil que pienso. Afortunadamente no es tan difícil. Bastante sencillo:

  • Analice el tipo de nombre en la definición de tipo y los argumentos de tipo genérico.
  • Obtenga el tipo genérico definición de objeto
  • obtener los objetos de tipo para cada argumento tipo genérico
  • Construir el tipo genérico de la definición de tipo genérico y los argumentos de tipo genérico, utilizando el método MakeGenericType en el objeto definición de tipo.
+0

Pensé en esta solución pero es el último paso que encuentro difícil, digamos que analicé Tuple'2 [System.String, MyNameSpace.MyType ] y puedo obtener los tres tipos diferentes (Tuple, String y MyType). ¿Cómo creo la instancia t de Tipo como: t == typeof (Tuple ) –

+4

Tipo genericType = typeof (Dictionary <,>); Escriba constructedType = genericType.MakeGenericType (new Type [] {typeof (String), typeof (String)}); –

+0

"Directo" hasta que tenga en cuenta la recursividad. ;) – Lazlo

5

Algo como esto ....

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

por ejemplo

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

o, como dice Eric .. si usted tiene los tipos de cambio, simplemente construirlo ..

Type genericType = typeof(Dictionary<,>); 
Type constructedType = genericType.MakeGenericType(new Type[] { typeof(String), typeof(String) }); 
+0

* no hay información sobre el ensamblado en la cadena * –

+0

, entonces, a menos que el ensamblaje esté cargado o puede cargarlo Y no hay coincidencias ambiguas, no tiene suerte. lo siento. –

+0

¿es posible forzar la carga de los conjuntos? –

1

Si el formato es't1 [[t2, a2] [t3, a3]], A1 ', esto funciona:

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

Aquí está mi solución manera difícil de conseguir cualquier tipo:

/// <summary> 
    /// Gets the type associated with the specified name. 
    /// </summary> 
    /// <param name="typeName">Full name of the type.</param> 
    /// <param name="type">The type.</param> 
    /// <param name="customAssemblies">Additional loaded assemblies (optional).</param> 
    /// <returns>Returns <c>true</c> if the type was found; otherwise <c>false</c>.</returns> 
    public static bool TryGetTypeByName(string typeName, out Type type, params Assembly[] customAssemblies) 
    { 
     if (typeName.Contains("Version=") 
      && !typeName.Contains("`")) 
     { 
      // remove full qualified assembly type name 
      typeName = typeName.Substring(0, typeName.IndexOf(',')); 
     } 

     type = Type.GetType(typeName); 

     if (type == null) 
     { 
      type = GetTypeFromAssemblies(typeName, customAssemblies); 
     } 

     // try get generic types 
     if (type == null 
      && typeName.Contains("`")) 
     { 
      var match = Regex.Match(typeName, "(?<MainType>.+`(?<ParamCount>[0-9]+))\\[(?<Types>.*)\\]"); 

      if (match.Success) 
      { 
       int genericParameterCount = int.Parse(match.Groups["ParamCount"].Value); 
       string genericDef = match.Groups["Types"].Value; 
       List<string> typeArgs = new List<string>(genericParameterCount); 
       foreach (Match typeArgMatch in Regex.Matches(genericDef, "\\[(?<Type>.*?)\\],?")) 
       { 
        if (typeArgMatch.Success) 
        { 
         typeArgs.Add(typeArgMatch.Groups["Type"].Value.Trim()); 
        } 
       } 

       Type[] genericArgumentTypes = new Type[typeArgs.Count]; 
       for (int genTypeIndex = 0; genTypeIndex < typeArgs.Count; genTypeIndex++) 
       { 
        Type genericType; 
        if (TryGetTypeByName(typeArgs[genTypeIndex], out genericType, customAssemblies)) 
        { 
         genericArgumentTypes[genTypeIndex] = genericType; 
        } 
        else 
        { 
         // cant find generic type 
         return false; 
        } 
       } 

       string genericTypeString = match.Groups["MainType"].Value; 
       Type genericMainType; 
       if (TryGetTypeByName(genericTypeString, out genericMainType)) 
       { 
        // make generic type 
        type = genericMainType.MakeGenericType(genericArgumentTypes); 
       } 
      } 
     } 

     return type != null; 
    } 

    private static Type GetTypeFromAssemblies(string typeName, params Assembly[] customAssemblies) 
    { 
     Type type = null; 

     if (customAssemblies != null 
      && customAssemblies.Length > 0) 
     { 
      foreach (var assembly in customAssemblies) 
      { 
       type = assembly.GetType(typeName); 

       if (type != null) 
        return type; 
      } 
     } 

     var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); 
     foreach (var assembly in loadedAssemblies) 
     { 
      type = assembly.GetType(typeName); 

      if (type != null) 
       return type; 
     }   

     return type; 
    } 
+0

genial !! Gracias por eso – henon

Cuestiones relacionadas