Search code examples
c#reflection

C# Reflection: how to get List<Employee> instead of System.Collections.Generic.List`1[Employee]?


I am trying to use reflection to query the public interface of a class library, then produce classes and methods from info in the query.

The problem is that the generated source code won't compile:

  • The original class library has a function parameter being "List<Employee>", but the generated source code has "System.Collections.Generic.List`1[Employee]". It is generated by Type.ToString().

  • The original class library has "Dictionary<string, Employee>", but the generated code has "System.Collections.Generic.Dictionary`2[string, Employee]".

Here is the reflection code to generate source code:

            foreach (MethodInfo methodInfo in type.GetMethods())
            {
                if (!methodInfo.IsStatic)
                    continue;

                Console.Write($"    {(methodInfo.IsStatic ? "static" : "")} {methodInfo.ReturnType} {methodInfo.Name} (");
                ParameterInfo[] aParams = methodInfo.GetParameters();

                for (int i = 0; i < aParams.Length; i++)
                {
                    ParameterInfo param = aParams[i];

                    if (i > 0)
                        Console.Write(", ");

                    string strRefOrOut;

                    if (param.ParameterType.IsByRef)
                    {
                        if (param.IsOut)
                            strRefOrOut = "out ";
                        else
                            strRefOrOut = "ref ";
                    }
                    else
                        strRefOrOut = "";

                    Console.Write($"{ strRefOrOut }{ param.ParameterType.ToString() } {param.Name}");
                }

                Console.WriteLine(");");
            }

It produces the following source code that cannot be compiled:

static System.Void Test1 (System.Collections.Generic.List`1[Employee] employees);
static System.Void Test (System.Collections.Generic.Dictionary`2[System.String, Employee] dict);

I want it to be

static System.Void Test1 (List<Employee> employees);
static System.Void Test (Dictionary<System.String, Employee> dict);

How do I get the desired outcome from the Type?

I don't want to do ugly "if/else if/else if/else" string manipulations to convert them, because if I forget to include a type of collection then it will break.

Is there an elegant way of automatically get the former, such as Type.ProperName?


Solution

  • If you don't want what Reflection provides directly then you need to write your own method to do what you actually want. Here's an example that will generate C#-style names for most types, so you can just call it every time and get the correct result:

    private static string GetTypeName(Type type)
    {
        var typeName = type.Name;
    
        if (!type.IsGenericType)
        {
            return typeName;
        }
    
        typeName = typeName.Substring(0, typeName.IndexOf('`'));
    
        var parameterTypeNames = type.GetGenericArguments().Select(GetTypeName);
    
        typeName = $"{typeName}<{string.Join(", ", parameterTypeNames)}>";
    
        return typeName;
    }
    

    This ignores namespaces and use .NET names, e.g. "String" rather than "string". You can change those things if you want. If you do omit namespaces, you'd have to make sure that appropriate imports were written too.