Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does typeof(string[][,]).Name return String[,][] [duplicate]

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 952
Rest Wing Avatar asked Jul 30 '12 11:07

Rest Wing


People also ask

Does typeof return a string?

The typeof operator returns a string indicating the type of the unevaluated operand.

Which type does the typeof operator return?

In JavaScript, the typeof operator returns the data type of its operand in the form of a string. The operand can be any object, function, or variable.

What is typeof() in js?

typeof is a JavaScript keyword that will return the type of a variable when you call it. You can use this to validate function parameters or check if variables are defined. There are other uses as well. The typeof operator is useful because it is an easy way to check the type of a variable in your code.

What does typeof null returns?

The data type of null is object. The data type of an undefined variable is undefined * The data type of a variable that has not been assigned a value is also undefined *


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 160
O. R. Mapper Avatar answered Sep 25 '22 16:09

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 33
Wai Ha Lee Avatar answered Sep 25 '22 16:09

Wai Ha Lee