如何从复杂的完整路径字符串中找到System.Type?

时间:2018-08-30 09:26:20

标签: c# reflection system.type

例如,我的类型是一个复杂类型,它是一个泛型类型。

public class TestType<T> : xxx
{
}

这是Assmebly A中的泛型类。 我的程序集B参考A,还有另一个类型TestObject。 所以实际的类型是:

TestType<TestObject>

... 如果我保存此类型的全名,则它是一个非常复杂的字符串,如下所示:

BluePrint.Core.CustomObjectConverter`1[[BluePrint.SGame.VInt2, BluePrint.SGame.Plugins, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], BluePrint.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

那么,如果我想找到此字符串的System.Type,该怎么做? 我使用System.Type.GetType,它返回null。 通用类型和参数类型在不同的程序集中。

2 个答案:

答案 0 :(得分:0)

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

我在这里找到解决方案: Loading a generic type by name when the generics arguments come from multiple assemblies

答案 1 :(得分:0)

如果具有通用类型,则需要一个接一个地执行此步骤。 首先,获取通用类型:

typeof(BluePrint.Core.CustomObjectConverter<>).FullName

这应该给你

"BluePrint.Core.CustomObjectConverter`1"

您可以将其传递给GetType

var genericType = Type.GetType("BluePrint.Core.CustomObjectConverter`1")

,然后获取其特定类型:

genericType.MakeGenericType("BluePrint.SGame.VInt2")

知道这一点,并且只有一个字符串时,您可以解析该字符串并在下一步骤之后建立您的类型。

如果尚未将程序集加载到您的空间中,则可以使用GetType的重载来找到它们:https://msdn.microsoft.com/en-us/library/ee332978(v=vs.110).aspx