代码之家  ›  专栏  ›  技术社区  ›  Cheick

当泛型参数来自多个程序集时,按名称加载泛型类型

  •  6
  • Cheick  · 技术社区  · 15 年前

    我只需要从它的全名创建一个类型,例如:“system.string”或“tuple'2[string,mytype]”。 字符串中没有关于程序集的信息。 这是代码的样子。

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

    此方法在类型不是泛型时工作。但是对于遍历程序集的泛型类型,总是失败,因为没有程序集包含生成该类型所需的所有定义。

    在调用gettypes时,是否有方法为类型解析提供多个程序集?

    4 回复  |  直到 11 年前
        1
  •  7
  •   Eric Lippert    15 年前

        2
  •  5
  •   Sky Sanders    15 年前

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

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

    Type genericType = typeof(Dictionary<,>);
    Type constructedType = genericType.MakeGenericType(new Type[] { typeof(String), typeof(String) });
    
        3
  •  2
  •   Lars Corneliussen    12 年前

    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);
    }
    
        4
  •  2
  •   Benni    11 年前

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