NoizWaves
NoizWaves

Reputation: 2680

How to get full C# declaration for a Type?

I'm trying to write a function to generate the full C# declaration for a Type object. My current method involves performing very manual and specific logic on the Type object.

Is there some built in way to .Net to generate this declaration?

As an example, take this class:

namespace My.Code.Here
{
   public class Class1<>
   {
      public enum Enum1 { }
   }
}

when the function (lets call it getCSharpDec) is called on typeof(Class1<>.Enum1), it would return "My.Code.Here.Class1<>.Enum1".

Upvotes: 1

Views: 1965

Answers (4)

Matthew Maddin
Matthew Maddin

Reputation:

This code should work for nested generic types (e.g. Foo<int>.Bar<string,object>).

public static string GetCSharpTypeName(this Type type, bool getFullName)
{
    StringBuilder sb = new StringBuilder();
    if (getFullName && !string.IsNullOrEmpty(type.Namespace))
    {
        sb.Append(type.Namespace);
        sb.Append(".");
    }
    AppendCSharpTypeName(sb, type, getFullName);
    return sb.ToString();
}

private static void AppendCSharpTypeName
    (StringBuilder sb, Type type, bool fullParameterNames)
{
    string typeName = type.Name;
    Type declaringType = type.DeclaringType;

    int declaringTypeArgumentCount = 0;
    if (type.IsNested)
    {
        if (declaringType.IsGenericTypeDefinition)
        {
            declaringTypeArgumentCount = 
                declaringType.GetGenericArguments().Length;
            declaringType = declaringType.MakeGenericType(
                type.GetGenericArguments().Take(declaringTypeArgumentCount)
                    .ToArray());
        }

        AppendCSharpTypeName(sb, declaringType, fullParameterNames);
        sb.Append(".");
    }
    Type[] genericArguments = type.GetGenericArguments()
        .Skip(declaringTypeArgumentCount).ToArray();

    int stopIndex;
    if ((type.IsGenericTypeDefinition || type.IsGenericType)
        && ((stopIndex = type.Name.IndexOf('`')) > 0))
    {
        sb.Append(typeName.Substring(0, stopIndex));
        string[] genericArgumentNames = genericArguments
            .Select(t => GetCSharpTypeName(t, fullParameterNames)).ToArray();
        if (genericArgumentNames.Length > 0)
            sb.AppendFormat("<{0}>", string.Join(",", genericArgumentNames));
    }
    else
    {
        sb.Append(typeName);
    }
}

Upvotes: 1

Marc Gravell
Marc Gravell

Reputation: 1063559

There are a couple of problems here...

  • C# and Type name nested types differently
  • C# and Type name generic types differently

As a minor aside, Class1<>.Enum1 isn't a closed type, but that shouldn't be an issue...

(edit)

This gets pretty close - it still retains the outer generics from the type, though:

static void Main()
{
    Type t = typeof(My.Code.Here.Class1<>.Enum1);
    string s = GetCSharpName(t); // My.Code.Here.Class1<T>.Enum1<T>
}

public static string GetCSharpName<T>()
{
    return GetCSharpName(typeof(T));
}
public static string GetCSharpName(Type type)
{
    StringBuilder sb = new StringBuilder();
    sb.Insert(0, GetCSharpTypeName(type));
    while (type.IsNested)
    {
        type = type.DeclaringType;
        sb.Insert(0, GetCSharpTypeName(type) + ".");

    }
    if(!string.IsNullOrEmpty(type.Namespace)) {
        sb.Insert(0, type.Namespace + ".");
    }
    return sb.ToString();
}
private static string GetCSharpTypeName(Type type)
{

    if (type.IsGenericTypeDefinition || type.IsGenericType)
    {
        StringBuilder sb = new StringBuilder();
        int cut = type.Name.IndexOf('`');
        sb.Append(cut > 0 ? type.Name.Substring(0, cut) : type.Name);

        Type[] genArgs = type.GetGenericArguments();
        if (genArgs.Length > 0)
        {
            sb.Append('<');
            for (int i = 0; i < genArgs.Length; i++)
            {
                sb.Append(GetCSharpTypeName(genArgs[i]));
                if (i > 0) sb.Append(',');
            }
            sb.Append('>');
        }
        return sb.ToString();
    }
    else
    {
        return type.Name;
    }
}

Upvotes: 5

Samuel Jack
Samuel Jack

Reputation: 33270

Type.FullName is what you're looking for.

Upvotes: 1

jerryjvl
jerryjvl

Reputation: 20151

Do you mean you want something like the typeof(Class1<>.Enum1).FullName?

Note though as Marc indicates, the name this gives you might not be exactly what you want if you need exactly the format you specified.

Upvotes: 0

Related Questions