Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to obtain base name of a generic type in .NET is through Substring?

If I have this:

Type t = typeof(Dictionary<String, String>);

How do I get "System.Collections.Generic.Dictionary" as a string? Is the best/only way to do this:

String n = t.FullName.Substring(0, t.FullName.IndexOf("`"));

Seems kinda hackish to me though.

The reason I want this is that I want to take a Type object, and produce code that is similar to the one found in a C# source code file. I'm producing some text templates, and I need to add types as strings into the source, and the FullName property produces something like this:

System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089]]

instead of what I want:

System.Collections.Generic.Dictionary<System.String, System.String>

Edit: Ok, here's the final code, still seems a bit like a hack to me, but it works:

/// <summary>
/// This method takes a type and produces a proper full type name for it, expanding generics properly.
/// </summary>
/// <param name="type">
/// The type to produce the full type name for.
/// </param>
/// <returns>
/// The type name for <paramref name="type"/> as a string.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <para><paramref name="type"/> is <c>null</c>.</para>
/// </exception>
public static String TypeToString(Type type)
{
    #region Parameter Validation

    if (Object.ReferenceEquals(null, type))
        throw new ArgumentNullException("type");

    #endregion

    if (type.IsGenericType)
    {
        if (type.GetGenericTypeDefinition() == typeof(Nullable<>))
        {
            Type underlyingType = type.GetGenericArguments()[0];
            return String.Format("{0}?", TypeToString(underlyingType));
        }
        String baseName = type.FullName.Substring(0, type.FullName.IndexOf("`"));
        return baseName + "<" + String.Join(", ", (from paramType in type.GetGenericArguments()
                                                   select TypeToString(paramType)).ToArray()) + ">";
    }
    else
    {
        return type.FullName;
    }
}
like image 936
Lasse V. Karlsen Avatar asked Aug 30 '09 16:08

Lasse V. Karlsen


People also ask

Which of the following is a generic type in C#?

In C#, generic means not specific to a particular data type. C# allows you to define generic classes, interfaces, abstract classes, fields, methods, static methods, properties, events, delegates, and operators using the type parameter and without the specific data type.

What are generic constraints in C#?

The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function. Constraints can specify interfaces, base classes, or require a generic type to be a reference, value, or unmanaged type.

How do you find a parameter type?

You can access the type of a specific parameter by using square brackets, in the same way you would access an array element at index. Here is an example of how you would use the Parameters utility type for 2 functions that take the same object as a parameter. Copied!


2 Answers

The problem is that you want a language specific notation, in this case C#.

IL syntax:     [mscorlib]System.Collections.Generic.Dictionary`2<class [mscorlib]System.String, class [mscorlib]System.String>
C# syntax:     System.Collections.Generic.Dictionary<System.String, System.String>
VB.NET syntax: System.Collections.Generic.Dictionary(Of System.String, system.String)

Maybe you can call a language service to get the string you want, but you're probably better of with generating the string yourself.

like image 71
JohannesH Avatar answered Oct 02 '22 18:10

JohannesH


You can use CodeDom to generate a more "normal" looking C#-style declaration.

CodeDomProvider csharpProvider = CodeDomProvider.CreateProvider("C#");
CodeTypeReference typeReference = new CodeTypeReference(typeof(Dictionary<string, int>));
CodeVariableDeclarationStatement variableDeclaration = new CodeVariableDeclarationStatement(typeReference, "dummy");
StringBuilder sb = new StringBuilder();
using (StringWriter writer = new StringWriter(sb))
{
    csharpProvider.GenerateCodeFromStatement(variableDeclaration, writer, new CodeGeneratorOptions());
}

sb.Replace(" dummy;", null);
Console.WriteLine(sb.ToString());

The above code has the following output:

System.Collections.Generic.Dictionary<string, int>    

That should get you most of what you want without any custom type-stringifying code.

like image 21
bobbymcr Avatar answered Oct 02 '22 19:10

bobbymcr