Domanda

Il codice è simile al seguente:

namespace Test
{
    public interface IMyClass
    {
        List<IMyClass> GetList();
    }

    public class MyClass : IMyClass
    {
        public List<IMyClass> GetList()
        {
            return new List<IMyClass>();
        }
    }
}

Quando eseguo Analisi del codice ricevo la seguente raccomandazione.

  

Avviso 3 CA1002: Microsoft.Design: modifica 'Elenco' in 'IMyClass.GetList ()' per utilizzare Collection, ReadOnlyCollection o KeyedCollection

Come devo risolvere questo e quali sono le buone pratiche qui?

È stato utile?

Soluzione

Per rispondere al " perché " parte della domanda sul perché non elenca < T > , i motivi sono a prova di futuro e semplicità API.

a prova di futuro

Elenco < T > non è progettato per essere facilmente estensibile mediante la sottoclasse di esso; è progettato per essere veloce per le implementazioni interne. Noterai che i metodi su di esso non sono virtuali e quindi non possono essere sovrascritti e non ci sono hook nel suo Aggiungi / Inserisci / Rimuovi operazioni.

Ciò significa che se in futuro è necessario modificare il comportamento della raccolta (ad es. per rifiutare oggetti null che le persone tentano di aggiungere o per eseguire lavori aggiuntivi quando ciò accade, ad esempio l'aggiornamento dello stato della classe), è necessario cambiare il tipo di raccolta che si ritorna a una sottoclasse, che sarà una rottura dell'interfaccia (ovviamente cambiare la semantica di cose come non consentire null può anche essere una modifica dell'interfaccia, ma cose come l'aggiornamento del proprio stato di classe interno non sarebbe ).

Quindi restituendo una classe che può essere facilmente suddivisa in sottoclassi come Collection < T > o un'interfaccia come IList < T > , ICollection < T > ; o IEnumerable < T > puoi modificare l'implementazione interna in un tipo di raccolta diverso per soddisfare le tue esigenze, senza violare il codice dei consumatori perché può comunque essere restituito come il tipo aspettiamo.

Semplicità API

Elenco < T > contiene molte operazioni utili come BinarySearch , Sort e così via. Tuttavia, se questa è una raccolta che stai esponendo, è probabile che controlli la semantica dell'elenco e non i consumatori. Quindi, sebbene la tua classe internamente possa aver bisogno di queste operazioni, è molto improbabile che i consumatori della tua classe vogliano (o addirittura dovrebbero) chiamarli.

In quanto tale, offrendo una classe o un'interfaccia di raccolta più semplice, riduci il numero di membri che gli utenti della tua API vedono e ne semplifica l'utilizzo.

Altri suggerimenti

Lo dichiarerei personalmente per restituire un'interfaccia piuttosto che una raccolta concreta. Se vuoi davvero accedere all'elenco, usa IList < T > . Altrimenti, considera ICollection < T > e IEnumerable < T > .

Si tratta principalmente di astrarre le proprie implementazioni invece di esporre l'oggetto List da manipolare direttamente.

Non è una buona pratica lasciare che altri oggetti (o persone) modifichino direttamente lo stato dei tuoi oggetti. Pensa ai getter / setter di proprietà.

Collezione - > Per la raccolta normale
ReadOnlyCollection - > Per le raccolte che non devono essere modificate
KeyedCollection - > Quando invece vuoi dizionari.

Come risolverlo dipende da cosa vuoi che faccia la tua classe e dallo scopo del metodo GetList (). Puoi elaborare?

In questo tipo di caso, di solito cerco di esporre la minima quantità di implementazione necessaria. Se i consumatori non hanno bisogno di sapere che stai effettivamente utilizzando un elenco, non è necessario restituire un elenco. Tornando come Microsoft suggerisce una raccolta, nascondi il fatto che stai utilizzando un elenco dai consumatori della tua classe e li isola da un cambiamento interno.

Non credo che nessuno abbia risposto al " perché " parte ancora ... quindi ecco qui. Il motivo "perché" tu " dovresti " usa una Collection < T > invece di un Elenco < T > perché se esponi un Elenco < T > , allora chiunque ottenga l'accesso al tuo oggetto puoi modificare gli elementi nella lista. Considerando che Collection < T > dovrebbe indicare che stai creando i tuoi metodi " Aggiungi " ;, " Rimuovi " ;, ecc.

Probabilmente non devi preoccuparti, perché probabilmente stai programmando l'interfaccia solo per te (o forse alcuni colleghi). Ecco un altro esempio che potrebbe avere senso.

Se si dispone di un array pubblico, ad esempio:

public int[] MyIntegers { get; }

Lo penseresti perché esiste solo un " get " che nessuno può sbagliare con i valori, ma non è vero. Chiunque può modificare i valori al suo interno in questo modo:

someObject.MyIngegers[3] = 12345;

Personalmente, userei Elenco < T > nella maggior parte dei casi. Ma se stai progettando una libreria di classi che stai per distribuire a sviluppatori casuali e devi fare affidamento sullo stato degli oggetti ... allora vorrai creare la tua collezione e bloccarla da lì: )

Qualcosa da aggiungere sebbene sia passato molto tempo da quando questo è stato chiesto.

Quando il tipo di elenco deriva da Elenco < T > anziché Collection < T > , non puoi implementare i metodi virtuali protetti che Collection < T > implementa. Ciò significa che il tipo derivato non può rispondere nel caso in cui vengano apportate modifiche all'elenco. Questo perché Elenco < T > presuppone che tu sia consapevole quando aggiungi o rimuovi elementi. Essere in grado di rispondere alle notifiche è un sovraccarico e quindi List < T > non lo offre.

Nei casi in cui il codice esterno ha accesso alla tua raccolta, potresti non avere il controllo di quando un articolo viene aggiunto o rimosso. Pertanto Collection < T > fornisce un modo per sapere quando l'elenco è stato modificato.

Non vedo alcun problema con la restituzione di qualcosa del genere

this.InternalData.Filter(crteria).ToList();

Se ho restituito una copia disconnessa di dati interni o un risultato separato di una query di dati, posso restituire List < TItem > senza esporre alcun dettaglio di implementazione, e consentire di utilizzare i dati restituiti nel modo più conveniente.

Ma questo dipende dal tipo di consumatore che mi aspetto: se si tratta di una griglia di dati simile, preferisco restituire IEnumerable < TItem > che sarà l'elenco copiato degli articoli comunque nella maggior parte dei casi :)

Beh, la classe Collection è in realtà solo una classe wrapper attorno ad altre raccolte per nascondere i dettagli dell'implementazione e altre funzionalità. Suppongo che ciò abbia a che fare con il modello di codifica che nasconde la proprietà in linguaggi orientati agli oggetti.

Penso che non dovresti preoccuparti, ma se vuoi davvero compiacere lo strumento di analisi del codice, fai quanto segue:

//using System.Collections.ObjectModel;

Collection<MyClass> myCollection = new Collection<MyClass>(myList);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top