2015-04-15 21 views
20

ho di nuovo da C# e hanno una domanda per quanto riguarda l'uso di "var"var non funzionerà con DataGridViewRow

Quando uso il seguente codice tutto funziona alla grande

foreach(DataGridViewRow row in myGrid.Rows) 
{ 
    if (row.Cells[2].Value.ToString().Contains("51000")) 
    { 
     row.Cells[0].Value = "X"; 
    } 
} 

Ma quando cambio DataGridViewRow a var ottengo ed errore che indica

'oggetto' non contiene la definizione di 'celle' e nessun metodo di estensione 'cellule' accettare un primo argumen t di tipo 'oggetto' potrebbe essere trovato (le manca un un riferimento all'assembly direttiva using o?)

+0

sembra che C# stia cercando di implicare il tipo sbagliato per DataGridViewRow, questo accade quando ci sono definizioni ambigue per myGrid.Rows – maximdumont

+0

Avrai lo stesso problema con 'foreach (var row in dt.Rows)' dove 'dt 'è un' DataTable', ma specificando esplicitamente 'foreach (Riga DataRow in dt.Rows)' funziona bene – Habib

risposta

13

È perché la proprietà GridView.Rows restituisce un tipo GridViewRowCollection.

In questo caso var non può dedurre dall'utilizzo che l'oggetto sarà un DataGridViewRow all'interno.

Fonte: GridView.Rows Property

+0

capito - grazie – Joaquin

5

DataGridViewRow.Rows è di tipo DataGridViewRowCollection, che non implementa IEnumerable<DataGridViewRow>, solo IEnumerable. E object è la migliore ipotesi che compilatore può dedurre quando non si specifica cast DataGridViewRow per row

+1

Corretto ... ma spiega perché solo l'implementazione di 'IEnumerable' provoca la definizione di' oggetto' ... –

+1

Corretto. Il richiedente si aspetterebbe che nel 2015 avremmo superato il vecchio .NET non generico di 1 giorni (.NET 2 e generici nel 2005). Ma con ['DataGridViewRowCollection'] (https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridviewrowcollection.aspx), no. –

28

myGrid.Rows è di tipo DataGridViewRowCollection.

Questa cosa è piuttosto vecchio, la sua definizione si legge:

public class DataGridViewRowCollection : ICollection, IEnumerable, IList 

Hai visto le interfacce non generici? Questa classe potrebbe implementare IList<DataGridViewRow> e quindi var semplicemente funzionerebbe, ma è legacy.

IEnumerable trasmette alcuna informazione circa il tipo di elemento, e la funzione di GetEnumerator non aiuta qui, perché restituisce un IEnumerator, mentre potrebbe restituire un IEnumerator<DataGridViewRow>.

In sostanza, il compilatore C# cerca una funzione GetEnumerator che restituisce un oggetto che ha una funzione e una proprietà MoveNextCurrent (o un'interfaccia IEnumerable<T>/IEnumerable una volta attuata in modo esplicito). Questo approccio duck-typing è per ragioni storiche, esisteva prima che i generici venissero introdotti nella lingua. La variabile di ciclo foreach sarà dello stesso tipo della proprietà Current. E all'interno di IEnumerator (la variante non generica), Current è di tipo object.

Specificando il tipo in modo esplicito:

foreach (DataGridViewRow row in myGrid.Rows) 

getta semplicemente il valore di ritorno di Current ad un DataGridViewRow, per mancanza di un meccanismo migliore.

Si potrebbe anche usare LINQ per ottenere lo stesso effetto, se si vuole veramente da usare che var parola chiave qui:

foreach (var row in myGrid.Rows.Cast<DataGridViewRow>()) 

Questo funziona, perché il metodo di estensione Enumerable.Cast<T> restituisce un IEnumerable<T>, che a sua volta utilizza IEnumerator<T> e T come tipo della proprietà Current dell'enumeratore, quindi le informazioni sul tipo vengono propagate.

Dubito che trarrai vantaggio da questi dettagli a questo punto, ma potresti voler tenerlo per ulteriore consultazione quando imparerai di più sulla lingua. Dovresti conoscere i metodi di estensione e i tipi generici per capire questo.

+0

Sì, ora vedo. Grazie per te in profonda spiegazione. – Joaquin

1

Se si modifica DataGridViewRow su Var C# non è sicuro che sia presente un array denominato celle. Per risolvere questo problema potresti lanciare var come DataGridViewRow ma è quasi sempre meglio usare il tipo se lo conosci, cerca online la sicurezza del tipo per ottenere maggiori informazioni.

+0

Sono d'accordo che usare il tipo è sempre meglio. Stavo solo armeggiando con il come e mi stavo chiedendo perché var non avrebbe funzionato, ma ora lo capisco - grazie – Joaquin

+1

'var' è sicuro dal tipo; non c'è niente di sbagliato nell'usarlo quando disponibile. Il * compilatore * deduce il tipo, quindi il codice viene compilato esattamente come se lo avessi specificato tu stesso. In realtà è solo zucchero sintattico per salvarti digitando nomi di classi lunghe (e per i tipi anonimi, ovviamente). – Blorgbeard