Question

Je me demande lequel de ceux-ci serait considéré comme le plus propre ou le meilleur à utiliser et pourquoi.

L’un d’eux expose la liste des passagers, ce qui permet à l’utilisateur d’ajouter et de supprimer des objets, etc. L’autre masque la liste et ne permet à l’utilisateur que de les énumérer et de les ajouter à l’aide d’une méthode spéciale.

Exemple 1

class Bus
{
    public IEnumerable<Person> Passengers { get { return passengers; } }
    private List<Passengers> passengers;

    public Bus()
    {
        passengers = new List<Passenger>();
    }

    public void AddPassenger(Passenger passenger)
    {
        passengers.Add(passenger);
    }
}

var bus = new Bus1();
bus.AddPassenger(new Passenger());
foreach(var passenger in bus.Passengers)
    Console.WriteLine(passenger);

Exemple 2

class Bus
{
    public List<Person> Passengers { get; private set; }

    public Bus()
    {
        Passengers = new List<Passenger>();
    }
}

var bus = new Bus();
bus.Passengers.Add(new Passenger());
foreach(var passenger in bus.Passengers)
    Console.WriteLine(passenger);

Je dirais que la première classe est mieux encapsulée. Et dans ce cas précis, cela pourrait être la meilleure approche (étant donné que vous devriez probablement vous assurer qu'il reste de la place dans le bus, etc.). Mais j'imagine qu'il pourrait y avoir des cas où la deuxième classe pourrait également être utile? Comme si la classe ne se souciait pas vraiment de ce qu'il adviendrait de cette liste tant qu'elle en aurait une. Qu'en penses-tu?

Était-ce utile?

La solution

Dans le premier exemple, il est possible de transformer votre collection.

Considérez ce qui suit:

var passengers = (List<Passenger>)bus.Passengers;

// Now I have control of the list!
passengers.Add(...);
passengers.Remove(...);

Pour résoudre ce problème, vous pouvez envisager quelque chose comme ceci:

class Bus
{
  private List<Passenger> passengers;

  // Never expose the original collection
  public IEnumerable<Passenger> Passengers
  {
     get { return passengers.Select(p => p); }  
  }

  // Or expose the original collection as read only
  public ReadOnlyCollection<Passenger> ReadOnlyPassengers
  {
     get { return passengers.AsReadOnly(); }
  }

  public void AddPassenger(Passenger passenger)
  {
     passengers.Add(passenger);
  }
 }

Autres conseils

Dans la plupart des cas, j'estime que l'exemple 2 est acceptable à condition que le type sous-jacent soit extensible et / ou exposé sous une forme quelconque d'événement onAdded / onRemoved afin que votre classe interne puisse répondre à toute modification apportée à la collection.

Dans ce cas, listez < T > ne convient pas car il est impossible pour la classe de savoir si quelque chose a été ajouté. Au lieu de cela, vous devriez utiliser une collection parce que la collection & Lt; T & Gt; La classe a plusieurs membres virtuels (Insérer, Supprimer, Définir, Effacer) qui peuvent être remplacés et des déclencheurs d’événements ajoutés pour notifier la classe d’enveloppement.

(Vous devez également savoir que les utilisateurs de la classe peuvent modifier les éléments de la liste / collection sans que la classe parent ne le sache, alors assurez-vous de ne pas vous fier aux éléments non modifiés. sont immuables évidemment - ou vous pouvez fournir des événements de style onChanged si vous en avez besoin.)

Exécutez vos exemples respectifs via FxCop, ce qui devrait vous donner une idée des risques d’exposition List<T>

Je dirais que tout dépend de votre situation. Je choisirais normalement l’option 2, car c’est la solution la plus simple, à moins que ne disposiez pas d’une raison professionnelle d’y ajouter des contrôles plus stricts.

L'option 2 est la plus simple, mais permet aux autres classes d'ajouter / supprimer des éléments à la collection, ce qui peut être dangereux.

Je pense qu’une bonne heuristique consiste à examiner ce que font les méthodes de wrapper. Si votre méthode AddPassenger (ou Remove, ou autres) ne fait que relayer l'appel à la collection, j'opterais pour la version la plus simple. Si vous devez vérifier les éléments avant de les insérer, l'option 1 est fondamentalement inévitable. Si vous devez garder une trace des éléments insérés / supprimés, vous pouvez aller dans les deux sens. Avec l'option 2, vous devez enregistrer des événements sur la collection pour obtenir des notifications, et avec l'option 1, vous devez créer des wrappers pour chaque opération de la liste que vous souhaitez utiliser (par exemple, si vous souhaitez insérer aussi bien que Ajouter), cela dépend.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top