Reputation: 2680
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
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
Reputation: 1063559
There are a couple of problems here...
Type
name nested types differentlyType
name generic types differentlyAs 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
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