Подтвердить что ты не робот

Неожиданное значение System.Type.FullName

Мне недавно нужно было создать специфическое имя С# (которое всегда должно включать глобальный спецификатор) для произвольного типа и произошло по следующей проблеме:

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

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

Я ожидал, что возвращаемое значение будет одинаковым в обоих случаях. Однако по какой-то причине связанная с массивом часть значения, кажется, обращена вспять (случай 1). Является ли это ожидаемым поведением в обратном направлении?

4b9b3361

Ответ 1

В то время как значение, возвращаемое Type.FullName, и идентификатор типа С# иногда бывает одинаковым, это не гарантируется. Имейте в виду, что Type.FullName возвращает одно и то же значение независимо от того, из какого языка CLI он вызывается, будь то С#, VB.NET, Oxygene или что-то еще.

Для многомерных и зубчатых массивов синтаксис С# перечисляет индексы в том порядке, в котором они записываются позже, тогда как синтаксис отражений возвращает то, что соответствует логической структуре массива. И (С#) string[,][,,][,,,] - это, в конце концов, значение типа string, из которого 4-мерный массив (т.е. string[,,,]), из которого 3-мерная матрица (т.е. string[,,,][,,]) и из нее a 2 -мерный массив (т.е. string[,,,][,,][,]).

Вместо того, чтобы полагаться на имя синтаксиса отражения, возвращаемое FullName, вы можете изучить свойства класса Type при анализе типов. Информация, такая как количество измерений или общие аргументы может быть извлечен оттуда.

При построении типов вы также можете использовать такие методы, как MakeArrayType или MakeGenericType для создания сложных типов во время выполнения без создания строки, содержащей ингредиенты для новых типов.

Некоторое содержание этого ответа было указано Марк Гравелл - спасибо!

Ответ 2

Примечание. Это не напрямую касается вашего вопроса.

Является ли это ожидаемое поведение отмены?

но я чувствую, что это добавляет к нему.


Вы можете использовать GenerateCodeFromExpression, чтобы вернуть строку, которая может быть использована для генерации кода для генерации типа для вас, например используя этот код (измененный этот ответ SO 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;
}

Предоставив codeDomProvider обработать строковое представление, вы можете быть уверены, что то, что сгенерировано, будет соответствовать тому, как вы должны определить тип.

Результаты с 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;

Результаты с FriendlyName

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

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

// returns "System.Collections.Generic.List<int>"
typeof(List<int>).FriendlyName();