using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Developpez.Dotnet.Collections
{
///
/// Représente une liste immuable d'objets. Toutes les méthodes qui modifient la liste
/// renvoient une copie modifiée.
///
/// Type des éléments de la liste
public class ImmutableList : IList, IEquatable>
{
#region Private data
private readonly IList _items;
private readonly int _hashCode;
#endregion
#region Constructor
///
/// Initialise une nouvelle instance de
///
/// Les éléments de la liste
public ImmutableList(IEnumerable items)
{
_items = items.ToArray();
_hashCode = ComputeHash();
}
#endregion
#region Public members
///
/// Renvoie une copie de la liste en y ajoutant l'élément spécifié
///
/// Elément à ajouter
/// La nouvelle liste
public ImmutableList Add(T item)
{
return this
.Append(item)
.AsImmutable();
}
///
/// Renvoie une copie de la liste en en retirant l'élément spécifié
///
/// Elément à retirer
/// La nouvelle liste
public ImmutableList Remove(T item)
{
return this
.SkipFirst(it => it.SafeEquals(item))
.AsImmutable();
}
///
/// Renvoie une copie de la liste en y insérant l'élément spécifié à la position spécifiée
///
/// Position à laquelle insérer l'élément
/// Elément à insérer
/// La nouvelle liste
public ImmutableList Insert(int index, T item)
{
return this
.InsertAt(index, item)
.AsImmutable();
}
///
/// Renvoie une copie de la liste en en retirant l'élément à la position spécifiée
///
/// Position de l'élément à retirer
/// La nouvelle liste
public ImmutableList RemoveAt(int index)
{
return this
.SkipAt(index)
.AsImmutable();
}
///
/// Renvoie une copie de la liste en remplaçant l'élément à la position spécifiée
///
/// Position à laquelle remplacer un élément
/// Elément qui remplace l'élément existant
/// La nouvelle liste
public ImmutableList Replace(int index, T item)
{
return this
.ReplaceAt(index, item)
.AsImmutable();
}
#endregion
#region Interface implementations
///
/// Renvoie la position de la première occurence de l'élément spécifié
///
/// Elément recherché
/// La position de l'élément s'il est présent dans la liste, sinon -1
public int IndexOf(T item)
{
if (_items == null)
return -1;
return _items.IndexOf(item);
}
///
/// Indique si la liste contient l'élément spécifié
///
/// Elément recherché
/// true si l'élément est présent dans la liste, sinon false
public bool Contains(T item)
{
if (_items == null)
return false;
return _items.Contains(item);
}
///
/// Copie les éléments de la liste vers le tableau spécifié
///
/// Tableau vers lequel les éléments sont copiés
/// Position dans le tableau à laquelle la copie commence
public void CopyTo(T[] array, int arrayIndex)
{
if (_items == null)
return;
_items.CopyTo(array, arrayIndex);
}
///
/// Renvoie le nombre d'éléments de la liste
///
public int Count
{
get
{
if (_items == null)
return 0;
return _items.Count;
}
}
///
/// Renvoie un énumérateur pour parcourir les éléments de la liste
///
/// Un énumérateur pour parcourir les éléments de la liste
public IEnumerator GetEnumerator()
{
if (_items == null)
return Enumerable.Empty().GetEnumerator();
return _items.GetEnumerator();
}
///
/// Détermine si cette liste est égale à la liste spécifiée. Deux listes immuables sont
/// considérées égales si et seulement si elles comportent les mêmes éléments dans le
/// même ordre.
///
/// La liste avec laquelle on compare la liste courante
/// true si les deux listes sont égales, false sinon
public bool Equals(ImmutableList other)
{
if (other == null || this._hashCode != other._hashCode)
return false;
return this.SequenceEqual(other);
}
#endregion
#region Explicit interface implementations
///
/// Opération non valide.
///
/// Position à laquelle insérer un élément
/// Elément à insérer
void IList.Insert(int index, T item)
{
throw new InvalidOperationException();
}
///
/// Opération non valide.
///
/// Position à laquelle supprimer un élément
void IList.RemoveAt(int index)
{
throw new InvalidOperationException();
}
///
/// Renvoie l'élément à la position spécifiée. L'accesseur set est une opération non valide.
///
/// Position de l'élément à accéder
/// La valeur de l'élément à l'index spécifié
T IList.this[int index]
{
get
{
if (_items == null)
throw new IndexOutOfRangeException();
return _items[index];
}
set
{
throw new InvalidOperationException();
}
}
///
/// Opération non valide.
///
/// Elément à ajouter
void ICollection.Add(T item)
{
throw new InvalidOperationException();
}
///
/// Opération non valide.
///
void ICollection.Clear()
{
throw new InvalidOperationException();
}
///
/// Indique si la collection est en lecture seule. Renvoie toujours true.
///
bool ICollection.IsReadOnly
{
get { return true; }
}
///
/// Opération non valide.
///
/// Elément à retirer
/// true si l'élément a été retiré, sinon false.
bool ICollection.Remove(T item)
{
throw new InvalidOperationException();
}
///
/// Renvoie un énumérateur pour parcourir les éléments de la liste
///
/// Un énumérateur pour parcourir les éléments de la liste
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
#region Overrides
///
/// Détermine si cette instance est égale à l'objet spécifié. Deux listes immuables sont
/// considérées égales si et seulement si elles comportent les mêmes éléments, dans le
/// même ordre.
///
/// L'objet avec lequel on compare cette instance
/// true si obj est égal à cette instance, sinon false
public override bool Equals(object obj)
{
if (obj is ImmutableList)
{
var other = (ImmutableList)obj;
return this.Equals(other);
}
return false;
}
///
/// Renvoie le code de hachage de cette liste.
///
/// Le code de hachage de cette liste
public override int GetHashCode()
{
return _hashCode;
}
#endregion
#region Private methods
private int ComputeHash()
{
return this.MakeHashCode(_items);
}
#endregion
}
///
/// Fournit des méthodes statiques pour créer des listes immuables
///
public static class ImmutableList
{
///
/// Crée une liste immuable à partir de la séquence spécifiée
///
/// Type des éléments
/// Séquence à partir de laquelle la liste immuable est crée
/// Une liste immuable contenant les éléments spécifiés
public static ImmutableList CreateFrom(IEnumerable source)
{
return new ImmutableList(source);
}
///
/// Crée une liste immuable à partir des éléments spécifiés
///
/// Type des éléments
/// Eléments à partir desquels la liste immuable est crée
/// Une liste immuable contenant les éléments spécifiés
public static ImmutableList Create(params T[] items)
{
return new ImmutableList(items);
}
///
/// Renvoie une liste immuable contenant les éléments d'une séquence
///
/// Type des éléments
/// Séquence à partir de laquelle la liste immuable est crée
/// Une liste immuable contenant les éléments de la séquence
public static ImmutableList AsImmutable(this IEnumerable source)
{
return new ImmutableList(source);
}
}
}