2013-03-25 3 views
16

Der Code unterhalb enthält eine einfache LINQ-Abfrage innerhalb einer unveränderlichen Struktur.Warum muss ich "dies" kopieren, wenn Sie LINQ in einer Struktur verwenden (und ist es OK, wenn ich das tue)?

struct Point 
{ 
    static readonly List</*enum*/> NeighborIndexes; 
    //and other readonly fields! 

    public IEnumerable<FlatRhombPoint> GetEdges() 
    { 
     return from neighborIndex in NeighborIndexes; 
      select GetEdge(neighborIndex); 
    } 
} 

Es kompiliert nicht.

Anonyme Methoden, Lambda-Ausdrücke und Abfrageausdrücke innerhalb von Strukturen können nicht auf Instanzmitglieder von 'this' zugreifen. Ziehen Sie in Erwägung, 'this' in eine lokale Variable außerhalb der anonymen Methode lambda Ausdruck oder Abfrageausdruck zu kopieren und stattdessen local zu verwenden.

Weiß jemand, warum dies nicht erlaubt ist?

Die die Meldung beheben schlägt funktioniert gut:

public IEnumerable<FlatRhombPoint> GetEdges() 
    { 
     var thisCopy = this; 

     return from neighborIndex in NeighborIndexes; 
      select thisCopy.GetEdge(neighborIndex); 
    } 

Aber ist dies gängige Praxis? Gibt es Gründe, solche Anfragen in Strukturen nicht zu haben? (In dem größeren Schema von Dingen, die eine Kopie machen, macht mich das als solche nicht leistungsmäßig beunruhigend).

+0

Warum nicht einfach auswählen this.GetEdge (NeighborIndex) ;? – antinescience

+1

+1 Interessante Frage. – feralin

+0

@antinescience, erklären sie in der Frage, dass sie einen Fehler bekommen, wenn sie "dieses" benutzen. –

Antwort

19

Instanzmethoden auf structs sind mit einem Referenz zu thisa hidden ref parameter genannt.
Dies ist der Grund, warum struct-Methoden in der Lage sind, die Strukturen, auf die sie zugreifen, zu mutieren.

Wenn Sie this (oder eine andere lokale Variable/Parameter) in einem Lambda-Ausdruck oder einer LINQ-Abfrage verwenden, wandelt der Compiler es in ein Feld auf einem compiler-generate closure class.

Die CLR unterstützt ref Felder nicht, so dass es unmöglich wäre, die erfassten this auf die gleiche Weise wie eine normale this zu arbeiten. (Dies ist auch der Grund, dass Sie nicht ref Parameter innerhalb lambdas verwenden)

Iteratormethoden haben das gleiche Problem – sie in eine versteckte enumerator Klasse kompiliert werden, und alle Variablen oder Parameter werden Felder in der Klasse (dies ist Warum Iteratoren ref Parameter nicht annehmen können).
Allerdings hat C# für Iteratoren die gegenteilige Entscheidung getroffen. In einem Iterator werden Sie can use this, aber es wird in ein Feld in der Enumerator-Klasse kopiert.
Dies bedeutet, dass wenn Sie eine Struktur innerhalb eines Iterators mutieren, die Mutationen nicht mit der Kopie des Aufrufers passieren.

+0

Hmmm danke, und interessant (wenn ein bisschen verwirrend). –

Verwandte Themen