Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected value of System.Type.FullName

I recently needed to build C# specific name (which must always include global:: specifier) for an arbitrary type and have come accross following issue:

// 1 - value: System.String[,,,][,,][,]
string unexpectedFullName = typeof( string[,][,,][,,,] ).FullName;      

// 2 - value: System.String[,][,,][,,,]
string expectedFullName = Type.GetType( "System.String[,][,,][,,,]" ).FullName;

I was expecting that returned value would be same in both cases. However, for some reason the array related part of the value seems to be reversed (case 1). Is this reversal expected behavior?

like image 856
Rest Wing Avatar asked Jul 30 '12 11:07

Rest Wing


2 Answers

While the value returned by Type.FullName and the C# type identifier sometimes happen to be the same, this is not guaranteed. Keep in mind that Type.FullName returns the same value regardless of what CLI language it is called from, be it C#, VB.NET, Oxygene or anything else.

For multidimensional and jagged arrays, C# syntax lists the indices in the order they are written later on, while reflection syntax returns something that matches the logical structure of the array. And a (C#) string[,][,,][,,,] is, after all, a value of type string, thereof a 4-dimensional array (i.e. string[,,,]), thereof a 3-dimensional array (i.e. string[,,,][,,]) and thereof a 2-dimensional array (i.e. string[,,,][,,][,]).

Rather than relying on the reflection syntax name returned by FullName, you might want to examine the properties of the Type class when analyzing types. Information such as the number of dimensions or the generic arguments can be retrieved from there.

When constructing types, you can also use methods such as MakeArrayType or MakeGenericType to create complex types at runtime without constructing a string that contains the ingredients for the new types.

Some of the contents of this answer was pointed out by Marc Gravell - thank you!

like image 178
O. R. Mapper Avatar answered Oct 18 '22 23:10

O. R. Mapper


Note: This doesn't directly address your question

Is this reversal expected behavior?

but I feel it adds to it.


You can use GenerateCodeFromExpression to return a string which could be used to generate the code to generate the type for you, for instance using this code (modified from this SO answer by hvd):

/// <summary>
/// <para>Returns a readable name for this type.</para>
/// <para>e.g. for type = typeof(IEnumerable&lt;IComparable&lt;int&gt;&gt;),</para>
/// <para>type.FriendlyName() returns System.Collections.Generic.IEnumerable&lt;System.IComparable&lt;int&gt;&gt;</para>
/// <para>type.Name returns IEnumerable`1</para>
/// <para>type.FullName() returns System.Collections.Generic.IEnumerable`1[[System.IComparable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]</para>
/// </summary>
public static string FriendlyName(this Type type)
{
    string result;

    using ( var codeDomProvider = CodeDomProvider.CreateProvider("C#") )
    {
        var typeReferenceExpression = new CodeTypeReferenceExpression(new CodeTypeReference(type));
        using ( var writer = new StringWriter() )
        {
            codeDomProvider.GenerateCodeFromExpression(typeReferenceExpression, writer, new CodeGeneratorOptions());
            result = writer.GetStringBuilder().ToString();
        }
    }

    return result;
}

By letting codeDomProvider handle the string representation, you can be sure that what's generated will match how you'd define the Type.

Results with FullName:

// returns "System.String[,,,][,,][,]"
typeof(string[,][, ,][, , ,]).FullName; 

// returns "System.String[,][,,][,,,]"
typeof(string[, , ,][, ,][,]).FullName;

// returns "System.Collections.Generic.List`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"
typeof(List<int>).FullName;

Results with FriendlyName

// returns "string[,][,,][,,,]"
typeof(string[,][, ,][, , ,]).FriendlyName(); 

// returns "string[,,,][,,][,]"
typeof(string[, , ,][, ,][,]).FriendlyName(); 

// returns "System.Collections.Generic.List<int>"
typeof(List<int>).FriendlyName();
like image 38
Wai Ha Lee Avatar answered Oct 19 '22 00:10

Wai Ha Lee