2013-02-10 8 views
6

Ich arbeite an einem kleinen Projekt mit ein paar verschiedenen Arten von Arrays (zB double[], float[], int[]). Für die Verifizierung/Test/Vernunft, Drucke ich einige dieser Arrays auf der Konsole, wie ich mitfahre. Also habe ich mehrere Funktionen haben, die unten wie diese aussehen (für dieses Beispiel vereinfacht - davon ausgehen, ich bin nur mit Single-Dimension-Arrays zu tun):Warum kann System.Array keine Typbeschränkung sein?

void Print(float[] a) // prints an array of floats 
{ 
    for (int i = 0; i < a.Length; i++) 
    { 
     Console.Write(a[i]); 
    } 
} 

void Print(double[] a) // prints an array of doubles 
{ 
    for (int i = 0; i < a.Length; i++) 
    { 
     Console.Write(a[i]); 
    } 
} 

ich in meiner unendlichen Weisheit, dachte ich einige der verringern könnte Code-Duplizierung durch einfaches Erstellen einer generischen Version dieser Funktionen.So habe ich es versucht:

void Print<T>(T t) where T : Array 
{ 
    for (int i = 0; i < t.Length; i++) 
    { 
     Console.Write(t.GetValue(i)); 
    } 
} 

Intellisense ist nicht beschweren, aber der Compiler nicht mit einem sehr interessanten Fehler:

Constraint cannot be special class 'System.Array'

Ich habe nach einer Erklärung (ähnlich Object oder versiegelte Klassen sieht, habe aber nicht viel gefunden, nicht nur ein Erwähnen Sie on msdn. Kann mir jemand erklären warum das ist der Fall? Warum kann ich keine Typbeschränkung von System.Array angeben?

ps: Während dies aus der Eingabe, erkannte ich, dass ich erreichen kann, was ich wollte, leichter, ursprünglich mit einer einfachen Funktion wie folgt aus:

void Print(System.Array a) 
{ 
    for (int i = 0; i < a.Length; i++) 
    { 
     Console.Write(a.GetValue(i)); 
    } 
} 

Aus diesem Grund für Arrays in den Compiler eine spezielle Regel gibt es ?

Antwort

16

Die entsprechende Syntax zu tun, was Sie wollen, ist dies:

void Print<T>(T[] array) 
{ 
    for (int i = 0; i < array.Length; i++) 
    { 
     Console.Write(array[i]); 
    } 
} 
+1

Macht Sinn, aber ich bin immer noch neugierig _why_ Ich kann nicht eine Basisklasse Typ Einschränkung von 'Array' ... – vlad

+0

Auch aus Neugier, ist das anders als die Verwendung eines Parameters des Typs' Array'? Gibt es etwas Boxen, wenn ich 'Array' benutze? – vlad

+1

@vlad Da es sich bei Arrays um Referenztypen und nicht um Werttypen handelt, gibt es kein Boxing, obwohl Sie die Objekte, die Sie daraus erhalten, im Gegensatz zu einem typisierten Array einbetten. Es ist auch nicht dasselbe, da ein 'Array' auch ein 2, 3 oder N-dimensionales Array oder ein Array sein kann, das nicht 0-indexiert ist. – Servy

1

Wenn die Frage wörtlich genommen, es sinnlos wäre, einen Array Zwang zu haben. Es ist das Gleiche wie es nutzlos ist, eine ValueType-Einschränkung zu haben, da es nicht überprüft, ob Sie einen Werttyp als generisches Argument verwenden, sondern ob der Typ, den Sie übergeben, ValueType zuweisbar ist.
So können Sie auch Array als das allgemeine Argument übergeben und es ist OK.

Was tatsächlich nützlich ist, ist ein Array contraint haben jede Art ermöglicht, die von Array leitet, aber nicht Array selbst:

void Print<TArr>(TArr t) where TArr : array //or [*] or other fancy syntax 

Wo T kann [] sein, [,], [,,], [,,,], und so auf. Der einzige nicht-generische Array Parameter ist, dass wir den Elementtyp des Arrays kennen.

Ein anderer Weg, dies zu lösen, ist eine benutzerdefinierte Array<T> Klasse mit impliziter Operator Überlastungen von T[], T[,], T[,,] usw.

bearbeiten zu erstellen:
Es gibt keine Möglichkeit, dies zu erreichen, auch in CIL (derzeit), weil sich int[,] und Array nicht in irgendwelchen Schnittstellen oder Konstruktoren unterscheiden. Wir brauchen where T : Array but not Array itself contraint.

+0

Es wäre nicht ganz nutzlos. Wäre da nicht das Verbot, könnte man ein CopyAndReverseArraySegment (T dest, T source, int start, int length) schreiben, wobei T: System.Array 'und es Aufrufe annehmen würde, bei denen entweder die Quelle oder das Ziel' war System.Array', lehnen aber immer noch Aufrufe ab, bei denen 'source' und' dest' inkompatible Array-Typen sind. So wie es ist, glaube ich nicht, dass es eine Möglichkeit gibt, "System.Array" als einen bestimmten Typ für einen der Parameter zuzulassen, ohne dass irgendein Derivat dieses Typs ebenfalls als akzeptabel angesehen wird. – supercat

Verwandte Themen