2015-12-10 6 views
10

Ich war a blog von Eric Lippert zu lesen, wo er erklärt, warum er so gut wie nie Arrays verwenden und das folgende Teil hat mich neugierig:Was nutzt AsEnumerable() für ein Array?

Wenn Sie eine solche API schreiben, wickeln Sie das Array in eine Readonlycollection und Rückkehr ein IEnumerable oder ein IList oder etwas, aber kein Array. (Und natürlich, nicht einfach das Array auf IEnumerable zu werfen und denke, du bist fertig! Das ist immer noch Variablen ausgibt; der Anrufer kann einfach zurück in Array! Nur ein Array übergeben, wenn es von einem eingewickelt ist nur-Lese-Objekt)

so wurde ich mit einer Sammlung um ein bisschen durcheinander.

string[] array = new[] { "cat", "dog", "parrot" }; 
IEnumerable<string> test1 = array.AsEnumerable(); 
string[] secondArray = (string[])test1; 

//array1[0] is now also "whale" 
array[0] = "whale"; 

//11 interfaces 
var iArray = array.GetType().GetInterfaces(); 
//Still 11 interfaces?? 
var iTest1 = test1.GetType().GetInterfaces(); 

ich initialisieren ein Array und verwenden sie dann die AsEnumerable() Methode auf, um es zu einem IEnumerable zu konvertieren (oder so Ich dachte), aber wenn ich es in ein neues Array zurückgeworfen und einen Wert im ursprünglichen Array geändert habe, die Werte von test1 und secondArray wurden geändert in. Apparently Ich habe gerade 2 neue Verweise auf das Original-Array, anstatt eine neue IEnumerable ein bisschen wie ToArray() gibt ein neues Array.

Wenn ich die Schnittstellen des Arrays und IEnumerable vergleiche, haben sie beide die gleichen Schnittstellen. Warum hat Array diese Methode, wenn es überhaupt nichts tut? Ich weiß, AsEnumerable() hat seine Verwendung mit Linq-to-Entities, um die aufzählbaren Methoden zu erhalten, wenn Sie eine IQueryable haben, aber warum würde diese Methode zu einem Array hinzugefügt werden? Gibt es einen praktischen Nutzen für diese Methode?

Edit: Dieser Kommentar von Tim Schmelter wirft einen wirklich guten Punkt und sollte nicht unbemerkt bleiben:

„Es ist nicht so nutzlos Sie können die tatsächlichen Typ ändern, ohne den Rest des Codes zu brechen.. Sie können also das Array durch eine Datenbankabfrage oder -liste oder einen Hash-Satz oder was auch immer ersetzen, aber das AsEnumerable funktioniert immer und der Rest des Codes auch nach. Also ist das AsEnumerable wie ein Vertrag. "

+0

vielleicht diese Ihnen helfen können: http://stackoverflow.com/questions/2013846/why-use-asenumerable-rather-than-casting-to-ienumerablet – Domysee

+1

'Die AsEnumerable (IEnumerable ) Methode hat keinen anderen Effekt als den Kompilierungszeittyp der Quelle von einem Typ zu ändern, der IEnumerable zu IEnumerable sich selbst implementiert. https://msdn.microsoft.com/library/bb335435(v=vs.100).aspx –

+0

Und die Implikation von Das oben genannte (was ich zitiert habe) bedeutet, dass Sie es anders durchlaufen können. Nicht sicher, was es sonst noch bietet. –

Antwort

9

AsEnumerable ist nur eine Möglichkeit, den Wert auf IEnumerable<T> zu übertragen. Es erstellt kein neues Objekt. Die Implementierung der Methode ist wie folgt:

public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source) 
{ 
    return source; 
} 

Es wird überhaupt kein neues Objekt erstellt.

Gründe es ist nützlich:

  1. Wenn ein Objekt IEnumerable<T> implementiert, sondern auch eine Instanz Methode Select genannt hat, Where, etc., können Sie nicht die LINQ-Methode verwenden. AsEnumerable können Sie es in IEnumerable umwandeln, um solche Überlastungskonflikte zu vermeiden.

  2. Wenn Sie ein Objekt zu IEnumerable<T> (warum auch immer) werfen wollen, aber T ist ein anonymer Typ, Sie kann keinen Guss verwenden, benötigen Sie eine generische Methode, die sein generisches Argument ableiten kann zu tun es.

4

Der Zweck AsEnumerable ist ganz klar, wie sie in dem Servy's answer und diesem Beitrag zum Beispiel beschrieben: Why use .AsEnumerable() rather than casting to IEnumerable<T>?.

Die verbleibende Frage ist: Warum ist es auf IEnumerable<T> sichtbar? Dies ist einfach der Fall, weil die hier verwendete Erweiterungsmethode IEnumerable<T> als Typ verwendet, auf dem sie definiert ist. Sehen Sie es als ToString() auf einem string. Da string ein Objekt ist, leitet es das Verfahren ToString() ab, obwohl es im Fall eines string nutzlos ist. Hier bewirkt die Erweiterungsmethode diese "nutzlose" Verfügbarkeit der Methode.

+2

Es ist nicht so nutzlos. Sie können den tatsächlichen Typ ändern, ohne den Rest des Codes zu unterbrechen. Sie könnten also das Array durch eine Datenbankabfrage oder -liste oder einen Hash-Satz oder was auch immer ersetzen, aber das 'AsEnumerable' funktioniert immer und auch der Rest des Codes. Das 'AsEnumerable' ist also wie ein Vertrag. –

+1

Dies beantwortet nicht die gestellte Frage, es liefert nur tangential verwandte Informationen und sollte daher nur ein Kommentar sein. – Servy

+0

Tatsächlich hat Servy das gut abgedeckt. Ich wollte nur auf das "Warum hat Array diese Methode, wenn es überhaupt nichts tut?" Teil der Frage. Es hat in einigen Fällen einen Zweck, aber nicht alle. –

4

Sie haben hier ein paar gute Antworten; Ich dachte, ich würde ein paar unterstützende Punkte hinzufügen.

Erstens, FYI, eine "do nothing" -Methode wie diese, die immer ihr Argument zurückgibt, wird eine "Identität" genannt, aus dem offensichtlichen Grund, dass die Ausgabe identisch mit der Eingabe ist. Identitäten scheinen nutzlos, aber sie sind von Zeit zu Zeit nützlich.

Zweitens, wenn Sie ein Array in eine Nur-Lese-Sequenz drehen wollen, die nicht referentielle Identität mit dem Array verfügt, können Sie eine Identität Projektion tun:

var sequence = from item in array select item; 

oder äquivalent:

var sequence = array.Select(item => item); 

Beachten Sie, dass die Projektion hier eine Identität ist; Ich sagte, sie seien nützlich.

Normalerweise würde LINQ eine Identity-Projektion optimieren; wenn Sie sagen,

from item in array where whatever select item; 

dann die Identität Vorsprung am Ende nie erzeugt, weil es nur eine Verschwendung von Zeit. Das heißt, das bedeutet

array.Where(item => whatever) 

nicht

array.Where(item => whatever).Select(item => item) 

Aber der Compiler tut nicht die Identität Projektion in dem Fall zu unterdrücken, wo die select ist die nur Sache in der Abfrage, genau so, dass Sie können eine Projektion erstellen, die nicht in das ursprüngliche Array zurückgeworfen werden kann.

+0

Um also ein 'IEnumerable' zu ​​erhalten, ohne dass es sich um eine Referenz auf das ursprüngliche Array handelt, tun wir' array.Select (x => x) .AsEnumerable() '? –

+1

@AlexanderDerck 'AsEnumerable' ist nicht notwendig, die Projektion ist ausreichend. – InBetween