2012-07-30 15 views
20

Vor kurzem habe ich benötigt, um C# bestimmten Namen zu bauen (die immer global umfassen :: Bezeichner) für einen beliebigen Typ und haben accross folgende Frage kommen:Unerwarteter Wert von System.Type.FullName

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

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

Ich hatte erwartet, Der Rückgabewert wäre in beiden Fällen gleich. Aus irgendeinem Grund scheint der arraybezogene Teil des Werts jedoch umgekehrt zu sein (Fall 1). Ist diese Umkehrung erwartetes Verhalten?

+6

Ich habe vor über diese kommen; Es scheint, dass in C# Array-Indizes/Dimensionen in der Reihenfolge deklariert werden, in der Sie lesen, Reflektion gibt einen Typnamen zurück, der mit seiner logischen Struktur übereinstimmt. Und ein (C#) 'string [,] [,,] [,,,]' ist schließlich ein Wert vom Typ 'string', davon ein 4-dimensionales Array (dh' string [,,,] ') davon ein 3-dimensionales Array (dh 'string [,,,] [,,]') und davon ein 2-dimensionales Array (dh 'string [,,,] [,,] [,]'). –

+6

Alles, was er gesagt hat ^^^^. Die C# -Syntax ([ausführlich erklärt] (http://blogs.msdn.com/b/ericlippert/archive/2009/08/17/arrays-of-arrays.aspx)) ist nicht erforderlich, um die Reflektionsbenennung zu erreichen Konvention. Wenn Sie sich also mit Reflektion beschäftigen: Verwenden Sie die Reflektionsbenennung. In anderen Nachrichten sind verschachtelte Typen nicht "Outer.Inner", sondern "Outer + Inner" und Generics sind nicht "Foo <,,>", sondern 'Foo \' 3'. –

+0

Ich erzeuge Code basierend auf einigen Eingabetypen, so dass ich definitiv Informationen über Indizes/Dimensionen umkehren muss, die über die System.Type-Instanz bereitgestellt werden. –

Antwort

13

Während der von zurückgegebene Wert und die Kennung des C# -Typs manchmal identisch sind, ist dies nicht garantiert. Beachten Sie, dass Type.FullName unabhängig von der CLI-Sprache, von der es aufgerufen wird, den gleichen Wert zurückgibt, sei es C#, VB.NET, Oxygene oder irgendetwas anderes.

Bei mehrdimensionalen und zackigen Arrays listet die C# -Syntax die Indizes in der Reihenfolge auf, in der sie später geschrieben werden, während die Reflexionssyntax etwas zurückgibt, das der logischen Struktur des Arrays entspricht. Und ein (C#) string[,][,,][,,,] ist schließlich ein Wert des Typs string, davon eine 4-dimensionale Anordnung (d. H. string[,,,]), davon eine dreidimensionale Anordnung (d. H. string[,,,][,,]) und davon eine zweidimensionale Anordnung (d. H. string[,,,][,,][,]).

Anstatt sich auf den Namen der Reflektionssyntax zu verlassen, die von FullName zurückgegeben wird, möchten Sie möglicherweise die Eigenschaften der Klasse Type untersuchen, wenn Sie Typen analysieren. Informationen wie die number of dimensions oder die generic arguments können von dort abgerufen werden.

Beim Erstellen von Typen können Sie auch Methoden wie MakeArrayType oder MakeGenericType verwenden, um zur Laufzeit komplexe Typen zu erstellen, ohne eine Zeichenfolge zu erstellen, die die Bestandteile für die neuen Typen enthält.

Einige der Inhalte dieser Antwort wurde von Marc Gravell hingewiesen - danke!

2

Hinweis: Dies gilt nicht direkt adressiert Ihre Frage

Ist das Umkehrverhalten zu erwarten?

aber ich fühle es fügt zu ihm hinzu.


Sie GenerateCodeFromExpression verwenden können eine Zeichenfolge zurück, die verwendet werden könnten, um den Code zu erzeugen, um den Typ für Sie zu erzeugen, zum Beispiel mit diesem Code (modifiziert nach this SO answer von 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; 
} 

Indem Sie codeDomProvider die Zeichenfolgendarstellung behandeln lassen, können Sie sicher sein, dass das, was erzeugt wird, übereinstimmt, wie Sie den Typ definieren würden.

Ergebnisse mit 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; 

Ergebnisse mit FriendlyName

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

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

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