Question

Le code ressemble à celui ci-dessous:

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

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

Lorsque j'exécute l'analyse de code, j'obtiens la recommandation suivante.

  

Avertissement 3 CA1002: Microsoft.Design: modifiez la "Liste" dans "IMyClass.GetList ()" pour utiliser Collection, ReadOnlyCollection ou KeyedCollection

Comment résoudre ce problème et quelle est la bonne pratique dans ce domaine?

Était-ce utile?

La solution

Répondre au " pourquoi " Une partie de la question de savoir pourquoi ne pas répertorier < T > , les raisons en sont la pérennité et la simplicité des API.

Evolutif

La

liste < T > n'est pas conçue pour être facilement extensible en la sous-classant; il est conçu pour être rapide pour les implémentations internes. Vous remarquerez que les méthodes qu'il contient ne sont pas virtuelles et ne peuvent donc pas être remplacées. Il n'y a pas de points d'ancrage dans son Ajouter / Insérer / Supprimer . opérations.

Cela signifie que si vous devez modifier le comportement de la collection à l'avenir (par exemple, pour rejeter des objets nuls que des personnes tentent d'ajouter, ou pour effectuer un travail supplémentaire lorsque cela se produit, comme la mise à jour de votre état de classe), vous devez alors: changez le type de collection que vous retournez en une classe que vous pouvez sous-classe, ce qui constituera un changement d'interface révolutionnaire (bien sûr, changer la sémantique de choses telles que ne pas autoriser la valeur null peut également être un changement d'interface, mais des choses comme la mise à jour de votre état de classe interne ne le seraient pas ).

Donc, en retournant soit une classe qui peut être facilement sous-classée, telle que Collection < T > , soit une interface telle que IList < T > , ICollection < T > ; ou IEnumerable < T > , vous pouvez modifier votre implémentation interne afin qu'elle soit d'un type de collecte différent pour répondre à vos besoins, sans que le code du consommateur ne soit rompu, car elle peut toujours être renvoyée sous le type attendons.

Simplicité de l'API

Liste < T > contient de nombreuses opérations utiles telles que BinarySearch , Trier , etc. Cependant, s'il s'agit d'une collection que vous exposez, il est probable que vous contrôliez la sémantique de la liste, et non les consommateurs. Ainsi, bien que votre classe interne puisse avoir besoin de ces opérations, il est très peu probable que les consommateurs de votre classe veuillent (ou même devraient) les appeler.

En tant que tel, en proposant une classe ou une interface de collection plus simple, vous réduisez le nombre de membres que les utilisateurs de votre API voient et vous simplifiez leur utilisation.

Autres conseils

Je déclarerais personnellement qu'il renvoie une interface plutôt qu'une collection concrète. Si vous souhaitez vraiment accéder à la liste, utilisez IList < T > . Sinon, envisagez de ICollection < T > et IEnumerable < T > .

Il s'agit principalement d'abstraire vos propres implémentations au lieu d'exposer l'objet List à manipuler directement.

Ce n’est pas une bonne pratique de laisser d’autres objets (ou personnes) modifier directement l’état de vos objets. Pensez aux getters / setters de propriétés.

Collection - > Pour collection normale
ReadOnlyCollection - > Pour les collections qui ne devraient pas être modifiées
KeyedCollection - > Quand vous voulez des dictionnaires à la place.

La façon de résoudre ce problème dépend de ce que vous voulez que votre classe fasse et du but de la méthode GetList (). Pouvez-vous élaborer?

Dans ce type de cas, j'essaie généralement d'exposer le moins possible d'implémentation. Si les consommateurs n'ont pas besoin de savoir que vous utilisez réellement une liste, vous n'avez pas besoin de renvoyer une liste. En retournant comme Microsoft suggère une collection, vous masquez le fait que vous utilisez une liste des consommateurs de votre classe et vous les isolez contre un changement interne.

Je ne pense pas que quiconque ait répondu à la question "Pourquoi" partie encore ... alors voilà. La raison " pourquoi " vous " devriez " utilisez un Collection < T > au lieu d'une liste < T > , car si vous exposez une liste < T > , toute personne ayant accès à votre objet peut modifier les éléments de la liste. Attendu que Collection & T & g <; code> est censé indiquer que vous créez vos propres méthodes "Ajouter", "Supprimer", etc.

Vous n'avez probablement pas besoin de vous inquiéter à ce sujet, car vous ne codez probablement que l'interface (ou peut-être quelques collègues). Voici un autre exemple qui pourrait avoir un sens.

Si vous avez un tableau public, ex:

public int[] MyIntegers { get; }

On pourrait penser que parce qu’il n’ya qu’un "get" accesseur que personne ne peut jouer avec les valeurs, mais ce n'est pas vrai. Tout le monde peut changer les valeurs à l'intérieur, comme ceci:

someObject.MyIngegers[3] = 12345;

Personnellement, je n’utiliserais que Liste < T > dans la plupart des cas. Mais si vous concevez une bibliothèque de classes que vous allez distribuer à des développeurs aléatoires et que vous devez vous fier à l'état des objets ... vous voudrez alors créer votre propre collection et la verrouiller à partir de là: )

Quelque chose à ajouter même si cela fait longtemps que cela n'a pas été demandé.

Lorsque votre type de liste dérive de Liste < T > au lieu de Collection < T > , vous ne pouvez pas implémenter les méthodes virtuelles protégées que Collection < T > < implémente. Cela signifie que le type dérivé ne peut pas répondre si des modifications sont apportées à la liste. En effet, List < T > suppose que vous êtes averti lorsque vous ajoutez ou supprimez des éléments. Le fait de pouvoir répondre aux notifications est une surcharge et par conséquent, Liste < T > ne l'offre pas.

Dans les cas où le code externe a accès à votre collection, il est possible que vous ne puissiez pas contrôler le moment où un élément est ajouté ou supprimé. Par conséquent, Collection < T > vous permet de savoir quand votre liste a été modifiée.

Je ne vois aucun problème à renvoyer quelque chose comme

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

Si j'ai renvoyé une copie déconnectée de données internes ou un résultat détaché d'une requête de données, je peux retourner en toute sécurité List < TItem & sans exposer les détails de la mise en oeuvre, et permettent d’utiliser les données renvoyées de la manière la plus commode.

Mais cela dépend du type de consommateur auquel je m'attend - s'il s'agit d'une sorte de grille de données, je préfère renvoyer IEnumerable < TItem > , qui sera la liste des éléments copiés de toute façon dans la plupart des cas:)

Eh bien, la classe Collection n’est en réalité qu’une classe wrapper autour d’autres collections pour masquer les détails de leur implémentation et d’autres fonctionnalités. Je pense que cela a quelque chose à voir avec le motif de codage masquant les propriétés dans les langages orientés objet.

Je pense que vous ne devriez pas vous en inquiéter, mais si vous voulez vraiment faire plaisir à l'outil d'analyse de code, procédez comme suit:

//using System.Collections.ObjectModel;

Collection<MyClass> myCollection = new Collection<MyClass>(myList);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top