Accesseur de propriété "en lecture seule" en C#

j'ai la classe suivante:

class SampleClass
{
   private ArrayList mMyList;

   SampleClass()
   {
       // Initialize mMyList
   }

   public ArrayList MyList
   {
       get { return mMyList;}
   }
}

je veux que les utilisateurs puissent obtenir mMyList c'est pourquoi j'ai exposé le "get" via une propriété mais je ne veux pas que des changements soient apportés à l'objet (i.e.. MyList.Add(new Classe());) pour revenir dans ma classe.

je suppose que je peux retourner une copie de l'objet mais cela peut être lent et je suis à la recherche d'un moyen qui fournira une erreur de compilation informant l'utilisateur qu'ils ne devraient pas s'attendre à être en mesure de modifier le retour la valeur de la Propriété.

Est-ce possible?

19
demandé sur SLaks 2009-03-06 19:16:03

8 réponses

avec un ArrayList vous êtes assez limité parce qu'il n'y a pas de classe de collection readonly non-generic dans la BCL. La solution rapide et sale est de rendre un type de IEnumerable.

   public IEnumerable MyList
   {
       get { return mMyList;}
   }

cela n'empêchera pas en fait quelqu'un de lancer sur ArrayList mais il ne permettra pas les modifications par défaut non plus

Vous pouvez retourner une liste en lecture seule en appelant ArrayList.ReadOnly. Cependant, son type de retour est un ArrayList de sorte que l'utilisateur serait toujours en mesure de compiler avec. Ajouter mais cela produirait une erreur d'exécution.

25
répondu JaredPar 2009-03-06 16:17:40

ArrayList.ReadOnly () méthode pour construire et retourner un wrapper en lecture seule autour de la liste. il ne copiera pas la liste, mais il suffit de faire un papier d'emballage en lecture seule autour de lui. Afin d'obtenir une vérification du temps de compilation, vous voudrez probablement retourner l'emballage en lecture seule aussi IEnumerable que @Jared le suggère.

public IEnumerable MyList
{
     get { return ArrayList.ReadOnly(mMyList); }
}

Une collection qui est en lecture seule est simplement une collection avec un emballage qui empêche de modifier le collection. Si des modifications sont apportées le collection sous-jacente, la lecture seule la collecte reflète ces changements.

cette méthode est une opération O(1).

Référence

19
répondu tvanfosson 2009-03-06 16:34:28

juste pour développer la réponse de JaredPar. Comme il l'a dit, le retour du champ de recul réel n'est pas complètement sûr, puisque l'utilisateur est toujours en mesure de lancer dynamiquement le IEnumerable retour à la une ArrayList.

je voudrais écrire quelque chose comme ceci pour être sûr qu'aucune modification à la liste originale ne soit faite:

public IEnumerable MyList
{
    get
    {
         foreach (object o in mMyList)
             yield return o;
    }
}

encore une fois, j'utiliserais probablement aussi une liste générique (IEnumerable<T>) pour être complètement sécurisé.

10
répondu Tom Lokhorst 2009-03-06 17:18:25

un ReadOnlyCollection.

return new ReadOnlyCollection<object>(mMyList).

Vous pouvez aussi faire l' ReadOnlyCollection un champ, et il reflétera automatiquement les changements dans la liste sous-jacente. C'est la solution la plus efficace.

si vous savez que mMyList ne contient qu'un type d'objet (par exemple, il n'y a rien d'autre que des DateTimes), vous pouvez retourner un ReadOnlyCollection<DateTime> (ou autre) pour plus de sécurité. Si vous utilisez C# 3, vous pouvez simplement écrire

return new ReadOnlyCollection<DateTime>(mMyList.OfType<DateTime>().ToArray())

cependant, cela ne sera pas automatiquement mis à jour avec la liste sous-jacente, et est aussi moins efficace (il copiera la liste entière). La meilleure option est de faire de mMyList un générique List<T> (par exemple,List<DateTime>)

4
répondu SLaks 2009-03-06 17:50:02
4
répondu Svish 2009-03-06 17:54:46

Vous devez envelopper la valeur de retour en lecture seule collection.

1
répondu Mehrdad Afshari 2009-03-06 16:17:45

disponible auprès de .NET v2.0

    public ArrayList MyList { get; private set; }
0
répondu wloescher 2013-03-25 20:50:05

il suffit de rendre la propriété comme scellée (ou pas inheritable dans VB.NET) and readonly, like this:

   public sealed readonly ArrayList MyList
   {
       get { return mMyList;}
   }

N'oubliez pas non plus de faire en sorte que le champ de soutien soit aussi lisible:

   private readonly ArrayList mMyList;

Mais pour initialiser la valeur de mMyList, vous devez l'initialiser UNIQUEMENT dans le constructeur, comme dans cet exemple:

public SampleClass()
{
   // Initialize mMyList
   mMyList = new ArrayList();
}
-3
répondu Eriawan Kusumawardhono 2009-03-06 16:42:44