Si vous voulez interdire les opérations de modification au moment de la compilation, vous avez besoin d'une solution de type sécurité. Déclarer une interface pour les opérations autorisées publiquement.
Utilisez cette interface comme type de propriété. Puis déclarez une classe qui implémente cette interface et hérite de la classe de collection standard.
public interface IReadOnlyList<T>
{
T this[int index] { get; }
int Count { get; }
}
public class SafeList<T> : List<T>, IReadOnlyList<T> { }
En supposant que vous obtenez la définition d'interface droite, vous aurez pas besoin de mettre en œuvre quoi que ce soit à la main, comme la classe de base fournit déjà les mises en œuvre.
Utilisez cette classe dérivée comme type du champ qui stocke la valeur de la propriété.
public class A
{
private SafeList<string> _list = new SafeList<string>();
public IReadOnlyList<string>
{
get { return _list; }
}
}
Dans la classe A, vous pouvez utiliser directement _list
, et modifier de manière le contenu. Les clients de classe A ne pourront utiliser que le sous-ensemble des opérations disponibles via IReadOnlyList<T>
.
Pour votre exemple, vous utilisez SortedList au lieu de la liste, de sorte que l'interface doit probablement être
public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
V this[K index] { get; }
}
Je l'ai fait hériter IEnumerable aussi bien, qui est en lecture seule de toute façon, est parfaitement sûr . La classe de sécurité serait alors:
public class SafeSortedList<K, V> : SortedList<K, V>, IReadOnlyDictionary<K, V> { }
Mais sinon c'est la même idée. Mise à jour: juste remarqué que (pour une raison que je ne comprends pas) vous ne voulez pas interdire les opérations de modification - vous voulez juste interdire QUELQUES opérations de modification. Très étrange, mais c'est toujours la même solution. Quelles que soient les opérations que vous voulez autoriser, « les ouvrir » dans l'interface:
public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
V this[K index] { get; set; }
}
Bien sûr, c'est le mauvais nom pour l'interface maintenant ... pourquoi diable voudriez-vous interdire l'ajout par Ajouter mais pas l'interdire via l'indexeur? (L'indexeur peut être utilisé pour ajouter des éléments, tout comme la boîte de méthode Add.)
Mise à jour
De votre commentaire, je pense que vous voulez dire que vous voulez autoriser l'affectation à la valeur d'une clé existante/paire de valeurs, mais n'autorise pas l'affectation à une clé précédemment inconnue. Évidemment, comme les clés sont spécifiées à l'exécution par les chaînes, il n'y a aucun moyen d'attraper cela au moment de la compilation. Ainsi, vous pouvez aussi bien aller pour le contrôle d'exécution:
public class FixedSizeDictionaryWrapper<TKey, TValue> : IDictionary<TKey, TValue>
{
IDictionary<TKey, TValue> _realDictionary;
public FixedSizeDictionaryWrapper(IDictionary<TKey, TValue> realDictionary)
{
_realDictionary = realDictionary;
}
public TValue this[TKey key]
{
get { return _realDictionary[key]; }
set
{
if (!_realDictionary.Contains(key))
throw new InvalidOperationException();
_realDictionary[key] = value;
}
}
// Implement Add so it always throws InvalidOperationException
// implement all other dictionary methods to forward onto _realDictionary
}
Chaque fois que vous avez un dictionnaire ordinaire et que vous voulez remettre à une méthode que vous ne faites pas confiance à mettre à jour les valeurs existantes, l'envelopper dans un des celles-ci.
S'il vous plaît dites-moi que vous n'utilisez pas la notation sans-voyelles-permis sur une base quotidienne! Je suppose que c'était juste pour cet exemple. Je fais avec la notation au travail toute la journée que j'appelle "une voyelle permise, mais ce n'est pas toujours la première!"; c'est horrible à lire. – jcollum
Ouais, d'accord, mais c'est un vendredi après-midi ... – Alex