foreach l'insidioso



Le collezioni tipizzate hanno il pregio di permettere al compilatore di scoprire più bug già in compilazione

Per esempio il compilatore C# dovrebbe accorgersi del errore di questo codice grazie ai generics?






    interface IPersistent { ... }
    class Invoice : IPersistent { ... }
    class Order : IPersistent { ... }
...
            List<IPersistent> changedDocuments = new List<IPersistent>();
            ...
            changedDocuments.Add(anInvoice);
            changedDocuments.Add(anOrder);
            ...
            foreach (Invoice changedInvoice in changedDocuments)
            {
                ...
            }


La risposta è no perché tenta un downcast, ecco il codice IL:

L_002b: call instance !0 [mscorlib]System.Collections.Generic.List`1/Enumerator<class IPersistent>::get_Current() 
L_0030: castclass Invoice


Credevo di avere le allucinazioni, un attimo di distrazione, insieme a due colleghi curiosi degli internals del linguaggio abbiamo invece capito che è proprio cosi

Questo funzionamento è contro-intuitivo e anche rischioso perché nasconde il fatto che possono succedere errore di InvalidCast a  run-time
Non conosco ancora quale vantaggo da ne se ripaga lo svantaggio

Il comportamento che mi aspetto è che questo foreach accetti come tipo del elemento IPersistent o una sua classe base altrimenti dia errore a compile-time

 


Questo è pane per i denti di Adrian ;-)

Print | posted @ mercoledì 14 gennaio 2009 00:46

Comments on this entry:

Gravatar # re: foreach l'insidioso
by Tommaso Caldarola at 14/01/2009 11:07

Penso che in questo caso non è tanto la collection tipizzata, ma "vedere" cosa fa il foreach (nato prima).
Gravatar # re: foreach l'insidioso
by Federico at 14/01/2009 12:22

Ciao Luca, credo dipenda da come il compilatore C# traduce il foreach in IL. Se ricordo bene il risultato della compilazione è una sorta di ciclo while che utilizza un oggetto enumeratore ottenuto mediante l'interfaccia IEnumerable<T> implementata dall'oggetto lista. L'enumeratore è un oggetto che supporta IEnumerator<T> e restituisce ciascun elemento attraverso la proprietà Current che è di tipo T. Di ciascun elemento così ottenuto viene fatto il cast al tipo dichiarato nel foreach quindi effettivamente a runtime potrebbe verificarsi una InvalidCastException. I generics non possono prevenire il problema perché ovviamente una collezione List<T> potrebbe contenere oggetti di tipi diversi derivati da T ma questo non è noto a compile-time. Spero di essermi spiegato in modo comprensibile (e soprattutto di non aver preso un abbaglio). Ciao.
Comments have been closed on this topic.