2009-11-19 9 views
5

Un array tipizzato implementa entrambe le interfacce System.Collections.IList e System.Collections.Generic.ICollection<T>, che hanno entrambe le proprietà IsReadOnly. Ma cosa diavolo sta succedendo qui?Array.IsReadSolo inconsistente a seconda dell'implementazione dell'interfaccia

var array = new int[10]; 
Console.WriteLine(array.IsReadOnly); // prints "False" 

var list = (System.Collections.IList)array; 
Console.WriteLine(list.IsReadOnly); // prints "False" 

var collection = (System.Collections.Generic.ICollection<int>)array; 
Console.WriteLine(collection.IsReadOnly); // prints "True" 

La IList vista della matrice comporta come mi aspetto, restituendo lo stesso della matrice stessa, tuttavia la vista ICollection<T> dell'array restituisce true.

C'è qualche spiegazione razionale per questo comportamento, o è un bug di compilatore/CLR? (Sarei davvero sorpreso se fosse il secondo come immagineresti sarebbe stato già trovato in passato, ma è così contro-intuitivo che non riesco a pensare a quale potrebbe essere la spiegazione ...).

Sto usando C# 3.0/.NET 3.5 SP1.

+1

Interessante, le osservazioni per entrambi dicono "Una raccolta che è di sola lettura non consente l'aggiunta, la rimozione o la modifica di elementi dopo che la raccolta è stata creata.". E penso che la logica equivale a IsReadOnly =! CanAdd || ! CanRemove || ! CanEdit che dovrebbe restituire true perché è possibile sostituire il valore in un indice specificato della lista. –

+0

a ma di più, ma il documento Array.IsReadonly è esplicito .. "Questa proprietà è sempre falsa per tutti gli array." "Array implementa la proprietà IsReadOnly perché è richiesta dall'interfaccia System.Collections .. ::. IList Se è necessaria una raccolta di sola lettura, utilizzare una classe System.Collections che implementa System.Collections .. ::. Interfaccia di IList Una matrice di sola lettura non consente l'aggiunta, la rimozione o la modifica di elementi dopo la creazione della matrice. " –

risposta

4

C'è stata molta agonia per questa decisione, come evidente nei commenti su questo feedback article.

+0

Sembra che questo dia il ragionamento interno (che sembra essere "sappiamo che è spazzatura ma è troppo tardi nel ciclo di rilascio per fare qualcosa al riguardo"). Quindi è di progettazione, ma non buona. –

+3

collegamento all'articolo di feedback sembra essere rotto. c'è un altro link? –

0

La ragione di questo comportamento si riduce a System.Array aventi 2 proprietà isReadOnly

Il primo è una proprietà normale sull'array tipo. Questa proprietà soddisfa la proprietà IsReadOnly dell'interfaccia IList. Per qualsiasi ragione in 1.0 del CLR hanno ritenuto che la proprietà dovrebbe restituire true.

Il secondo è l'implementazione di proprietà esplicita per il tipo ICollection<T> (attualmente implementato da CLR IIRC). In questo caso IsReadOnly restituisce true perché il tipo Array non può soddisfare i metodi mutanti di ICollection<T> come aggiungere, chiaro, ecc ...

La vera domanda è perché il cambiamento tra le versioni? In realtà non lo so, ma la mia ipotesi è che gli autori hanno determinato che è più appropriato visualizzare lo Array come letto solo quando è visto come una raccolta separata. Mentre può soddisfare parte dei metodi mutabili, non può soddisfarli tutti. Quindi è più sicuro vederlo come readonly vs. mutable.

+0

La spiegazione che 'ICollection .IsReadOnly' restituisce true perché non può soddisfare tutti i metodi dell'interfaccia' ICollection 'non contiene realmente acqua perché' IList.IsReadOnly' restituisce false e non può soddisfare tutti i metodi di l'interfaccia 'IList'. Quindi non so ancora se si tratta di un bug, o se no, quale fosse la logica alla base della decisione. –

+0

@Greg, credo che questo rappresenti un cambiamento nel modo di pensare tra la v1 e la v2 del CLR. Probabilmente a causa di reclami dei clienti, anche se non riesco a trovare alcuna prova di ciò. – JaredPar

0

Dalla documentazione per l'Array Class:

In .NET Framework versione 2.0, la classe Array implementa le System.Collections.Generic.IList<T>, System.Collections.Generic.ICollection<T>, e System.Collections.Generic.IEnumerable<T> interfacce generiche. Le implementazioni vengono fornite agli array in fase di esecuzione e pertanto non sono visibili agli strumenti di compilazione della documentazione . Come risultato, i generici interfacce non appaiono nella sintassi dichiarazione per la classe Array , e non ci sono riferimento argomenti di elementi di interfaccia che sono accessibili solo per fusione un array tipo interfaccia generica (esplicite implementazioni di interfaccia). La chiave cosa di essere a conoscenza di quando lanci una matrice a una di queste interfacce è che i membri che aggiungono, inserire o rimuovere elementi gettano NotSupportedException.

Quindi, poiché le raccolte generiche non supportano l'aggiunta, l'inserimento o l'eliminazione, IsReadOnly restituisce true. Sul motivo per cui non restituisce false per System.Collections.IList?La mia ipotesi sarebbe che

var array = new int[10]; 
Console.WriteLine(array.IsReadOnly); // prints "True" 
array[0] = 5; // WTF? This is readonly. 

non era quello che volevano vedere. Quando hanno aggiunto le interfacce generiche nella v2, queste possono essere chiamate solo quando l'array è stato lanciato, quindi restituire true per quelle più sensate.

+0

Questo in realtà non risponde affatto alla domanda; non vi è alcuna giustificazione per il motivo per cui la proprietà IsReadOnly restituisce un valore diverso per l'array sottostante. –

+0

ha chiarito la mia risposta – Logan5

6

From MSDN:

IList è un discendente dell'interfaccia ICollection ed è l'interfaccia di base di tutti gli elenchi non generici. Le implementazioni di IList rientrano in tre categorie : sola lettura, dimensione fissa e di dimensioni variabili. Non è possibile modificare un IList di sola lettura. Un IList a dimensione fissa non consente l'aggiunta o la rimozione di elementi , ma consente la modifica di elementi esistenti . Un IList di dimensioni variabili consente l'aggiunta, la rimozione e la modifica di degli elementi .

L'ICollection < T> interfaccia non ha un indicizzatore, quindi una dimensione fissa ICollection < T> è automaticamente sola lettura - non c'è modo di modificare un elemento esistente.

Forse ICollection < T> .IsFixedSize sarebbe stato un nome di proprietà migliore rispetto ICollection < T> .IsReadOnly, ma entrambi implicano la stessa cosa - impossibile da aggiungere o rimuovere elementi, vale a dire lo stesso di IList.IsFixedSize.

Una matrice è un elenco di dimensioni fisse, ma non è di sola lettura in quanto è possibile modificare gli elementi.

Come ICollection < T>, è in sola lettura, dal momento che un ICollection < T> non ha modo di modificare gli elementi.

Questo può sembrare confuso, ma è coerente e logico.

Qual è leggermente incoerente è che il generico IList < T> interfaccia ha una proprietà IsReadOnly ereditato da ICollection < T> cui semantica sono quindi diverso dal IList.IsReadOnly non generico. Immagino che i progettisti fossero consapevoli di questa incoerenza ma non sono stati in grado di tornare indietro e modificare la semantica dell'IList non generico per ragioni di compatibilità all'indietro.

In sintesi, un IList può essere:

  • Variable-size.

    IList.IsFixedSize = false

    IList.IsReadOnly = false

    ICollection < T> .IsReadOnly = false

  • fissa dimensioni (ma elementi possono essere modificati, ad esempio una matrice)

    IList.IsFixedSize = true

    IList.IsReadOnly = false

    ICollection < T> .IsReadOnly = true

  • sola lettura (gli elementi non possono essere modificati)

    IList.IsFixedSize = true

    IList.IsReadOnly = true

    ICollection < T> .IsReadOnly = true

Problemi correlati