how to find the System.Type from a complex full path string?

369 views Asked by At

For example, my Type is a complex type, it is a generic type.

public class TestType<T> : xxx
{
}

this is a generic class in Assmebly A. my Assembly B reference A, there is another type TestObject. so the actual type is :

TestType<TestObject>

.... if i save the fullname of this type, it is a very complex string, like this:

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

so, if i want to find the System.Type of this string, how to do this? i use System.Type.GetType, it return null. the generic type and the parameter type are in different assemblies.

2

There are 2 answers

0
boo On
    /// <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;
    }

i have find solution here: Loading a generic type by name when the generics arguments come from multiple assemblies

0
Chris On

When you have generic types, you need to do this one step after the other. First, get the generic type:

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

this should give you

"BluePrint.Core.CustomObjectConverter`1"

you can pass this to GetType

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

and then get the specific type for it:

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

knowing this, and when you only have this string, you could parsing the string and building up your types one step after the next.

in case you have not yet loaded the assemblies into you space, you can use the overloads of GetType to find them: https://msdn.microsoft.com/en-us/library/ee332978(v=vs.110).aspx