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

发布于 2024-08-21 13:55:32 字数 906 浏览 3 评论 0原文

我需要仅从其全名创建一个类型,例如:“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 时提供多个程序集进行类型解析?

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 ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

临走之时 2024-08-28 13:55:32

你将不得不以我认为困难的方式去做。幸运的是,这并不难。非常简单:

  • 将类型名称解析为类型定义和泛型类型参数。
  • 获取泛型类型定义对象
  • 获取每个泛型类型参数的类型对象
  • 使用类型定义对象上的 MakeGenericType 方法从泛型类型定义和泛型类型参数构造泛型类型。

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.
无名指的心愿 2024-08-28 13:55:32

像这样的东西......

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

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) });
疏忽 2024-08-28 13:55:32

这是我获取任何类型的困难方法解决方案:

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

Here is my hard way solution to get any type:

    /// <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;
    }
月野兔 2024-08-28 13:55:32

如果格式为“t1[[t2, a2][t3, a3]], a1”,则有效:

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

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文