2012-07-30 16 views
20

Niedawno potrzebne do zbudowania nazwę C# konkretną (która zawsze musi zawierać globalny :: specyfikatora) dla dowolnego typu i pochodzić po drugiej stronie następującą kwestię:Nieoczekiwana wartość System.Type.FullName

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

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

spodziewałem ta zwrócona wartość byłaby taka sama w obu przypadkach. Jednak z jakiegoś powodu część związana z tablicą wydaje się być odwrócona (przypadek 1). Czy to oczekiwane zachowanie odwrócenia?

+6

natknąłem to wcześniej; wydaje się, że podczas gdy w C# deklarujesz indeksy/wymiary tablicy w kolejności, w której czytasz, odbicie zwraca nazwę typu, która pasuje do jej logicznej struktury. A (C#) 'string [,] [,,] [,,,,]' jest przecież wartością typu 'string', którego jest czterowymiarową tablicą (np.' String [,,,] ') , z tego 3-wymiarowa tablica (tj. "ciąg [,,,] [,,]") i tym samym dwuwymiarowa tablica (tj. "ciąg [,,,] [,,] [,]'). –

+6

Wszystko, co powiedział ^^^^. Składnia C# ([wyjaśniono szczegółowo w tym miejscu] (http://blogs.msdn.com/b/ericlippert/archive/2009/08/17/arrays-of-arrays.aspx)) nie jest wymagana, aby dopasować się do nazwy odbicia Konwencja. Więc jeśli masz do czynienia z refleksją: użyj nazwy refleksji. W innych wiadomościach typy zagnieżdżone to nie "Outer.Inner", ale "Outer + Inner" zamiast, a generics to nie 'Foo <,,>', ale 'Foo \' 3' zamiast tego. –

+0

Generuję kod na podstawie niektórych typów danych wejściowych, więc zdecydowanie będę musiał odwrócić informacje o indeksach/wymiarach dostarczanych przez instancję System.Type. –

Odpowiedz

13

Chociaż wartość zwrócona przez Type.FullName i identyfikator typu C# czasami bywają takie same, nie jest to gwarantowane. Należy pamiętać, że Type.FullName zwraca tę samą wartość niezależnie od tego, z jakiego języka CLI jest wywoływany, np. C#, VB.NET, Oxygene lub cokolwiek innego.

Dla tablic wielowymiarowych i poszarpanych, składnia C# wymienia indeksy w kolejności, w jakiej są one później pisane, podczas gdy składnia odbicia zwraca coś, co pasuje do logicznej struktury tablicy. A (C#) string[,][,,][,,,] jest w końcu wartością typu string, z których jest to tablica 4-wymiarowa (to znaczy string[,,,]), z której jest to tablica 3-wymiarowa (to znaczy string[,,,][,,]), a do niej tablica 2-wymiarowa (to jest string[,,,][,,][,]).

Zamiast polegać na nazwę składni odbicie zwróconej przez FullName, warto zbadać właściwości klasy Type analizując typy. Informacje takie jak number of dimensions lub generic arguments można pobrać stamtąd.

Podczas konstruowania typów można również używać metod takich, jak MakeArrayType lub MakeGenericType do tworzenia typów złożonych w środowisku wykonawczym bez konstruowania łańcucha zawierającego składniki dla nowych typów.

Niektóre z treści tej odpowiedzi zostały wskazane przez Marc Gravell - dziękuję!

2

Uwaga: to nie bezpośrednio zająć swoje pytanie

Czy to odwrócenie oczekiwane zachowanie?

ale czuję, że dodaje do niego.


Można użyć GenerateCodeFromExpression zwraca ciąg znaków, który może być używany do generowania kodu w celu wygenerowania typ dla ciebie, na przykład za pomocą tego kodu (modyfikowany this SO answer przez 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; 
} 

Dzięki temu, że codeDomProvider obsługuje reprezentację ciągów, , możesz być pewny, że to, co zostanie wygenerowane, będzie zgodne z definicją typu.

Wyniki z 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; 

Wyniki z FriendlyName

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

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

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