2013-03-25 13 views
16

Il codice contiene una query LINQ semplice all'interno di una struttura immutabile.Perché devo copiare "questo" quando uso LINQ in una struttura (e va bene se lo faccio)?

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

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

Non viene compilato.

I metodi anonimi, le espressioni lambda e le espressioni di query all'interno delle strutture non possono accedere ai membri dell'istanza di "this". Si consiglia di copiare 'this' su una variabile locale esterna al metodo anonimo, lambda espressione o espressione di query e utilizzare invece il locale.

Qualcuno sa perché questo non è consentito?

Il fissare il messaggio suggerisce funziona bene:

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

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

Ma è questa una pratica standard? Ci sono motivi per non avere query come questa nelle strutture? (Nel più grande schema di cose che fanno una copia non mi preoccupo delle prestazioni in quanto tale).

+0

Perché non usare solo selezionare this.GetEdge (neighborIndex) ;? – antinescience

+1

+1 Interessante domanda. – feralin

+0

@antinescience, spiegano nella domanda che ottengono un errore quando si usa 'this'. –

risposta

19

metodi di istanza su structs vengono chiamati con un riferimento a thisa hidden ref parameter.
Ecco perché i metodi struct sono in grado di mutare le strutture su cui sono chiamati.

Quando si utilizza this (o qualsiasi altra variabile/parametro locale) all'interno di un'espressione lambda o query LINQ, il compilatore lo trasforma in un campo su un compiler-generate closure class.

Il CLR non supporta i campi ref, quindi sarebbe impossibile per il catturato this funzionare allo stesso modo di un normale this. (questo è anche il motivo per cui non è possibile utilizzare i parametri ref all'interno di lambdas)

I metodi di Iterator hanno lo stesso problema – vengono compilati in una classe di enumeratore nascosta e tutte le variabili oi parametri diventano campi nella classe (questo è perché gli iteratori non possono prendere i parametri ref).
Tuttavia, per gli iteratori, C# ha preso la decisione opposta. All'interno di un iteratore, si can use this, ma verrà copiato in un campo sulla classe dell'enumeratore.
Ciò significa che se si muta una struttura all'interno di un iteratore, le mutazioni non si verificheranno nella copia del chiamante.

+0

Hmmm grazie, e interessante (anche se un po 'confuso). –

Problemi correlati