« Les méthodes d'extension » : différence entre les versions

De Banane Atomic
Aller à la navigationAller à la recherche
 
(13 versions intermédiaires par le même utilisateur non affichées)
Ligne 24 : Ligne 24 :


= Useful extension methods =
= Useful extension methods =
== CollectionExtensions ==
== CollectionExtension ==
<kode lang="cs" collapsed>
<filebox fn="CollectionExtension.cs" collapsed>
public static class CollectionExtensions
/// <summary>
/// Adds each item to the list.
/// </summary>
/// <remarks>
/// The <see cref="IList{T}" /> interface does not have AddRange in its contract, contrary to the <see cref="List{T}" /> implementation.
/// The latter uses an optimized routine for adding a range of elements, and naming this extension method AddRange too would give the wrong impression of performance.
/// Additionally, for collections that notify of their changes, AddRange reads as if there would be only one notification of change after all elements have been added, when in fact there would probably by as many notifications as items being added.
/// </remarks>
public static void AddEach<T>(this ICollection<T> collection, IEnumerable<T> elements)
{
{
     /// <summary>
     ArgumentNullException.ThrowIfNull(collection);
     /// Adds each item to the list.
     ArgumentNullException.ThrowIfNull(elements);
    /// </summary>
 
     /// <remarks>
     if (collection is List<T> list)
     /// The <see cref="IList{T}" /> interface does not have AddRange in its contract, contrary to the <see cref="List{T}" /> implementation.
     {
    /// The latter uses an optimized routine for adding a range of elements, and naming this extension method AddRange too would give the wrong impression of performance.
        list.AddRange(elements);
    /// Additionally, for collections that notify of their changes, AddRange reads as if there would be only one notification of change after all elements have been added, when in fact there would probably by as many notifications as items being added.
     }
     /// </remarks>
     else
     public static void AddEach<T>(this ICollection<T> collection, IEnumerable<T> elements)
     {
     {
         if (collection == null)
         foreach (var element in elements)
         {
         {
             throw new ArgumentNullException(nameof(collection));
             collection.Add(element);
         }
         }
    }
}


        if (elements == null)
/// <summary>
        {
/// Removes each item from the list.
            throw new ArgumentNullException(nameof(elements));
/// </summary>
        }
/// <remarks>
/// This method is not named RemoveRange, because it does not have the same purpose as <see cref="List{T}.RemoveRange" />.
/// </remarks>
public static void RemoveEach<T>(this ICollection<T> collection, IEnumerable<T> elements)
{
    ArgumentNullException.ThrowIfNull(collection);
    ArgumentNullException.ThrowIfNull(elements);


        if (collection is List<T> list)
    foreach (var element in elements)
        {
    {
            list.AddRange(elements);
        collection.Remove(element);
        }
        else
        {
            foreach (var element in elements)
            {
                collection.Add(element);
            }
        }
     }
     }
}
public static void Remove<T>(this ICollection<T> collection, Func<T, bool> predicate)
{
    ArgumentNullException.ThrowIfNull(collection);
    collection.RemoveEach(collection.Where(predicate));
}
public static void RemoveSingle<T>(this ICollection<T> collection, Func<T, bool> predicate)
{
    ArgumentNullException.ThrowIfNull(collection);
    collection.Remove(collection.Single(predicate));
}
</filebox>


    /// <summary>
== IEnumerableExtension ==
    /// Removes each item from the list.
<filebox fn='IEnumerableExtension.cs' collapsed>
    /// </summary>
/// <summary>
    /// <remarks>
/// Update the property value of the items of the collection.
    /// This method is not named RemoveRange, because it does not have the same purpose as <see cref="List{T}.RemoveRange" />.
/// </summary>
    /// </remarks>
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
    public static void RemoveEach<T>(this ICollection<T> collection, IEnumerable<T> elements)
{
    foreach (T item in source)
        action(item);
}
 
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
    foreach (T item in source)
     {
     {
         if (collection == null)
         action(item);
         {
         yield return item;
            throw new ArgumentNullException(nameof(collection));
    }
        }
}
 
/// <summary>
/// Sorts the elements of a sequence according to an element's property.
/// </summary>
public static IEnumerable<T> OrderBy<T>(
    this IEnumerable<T> source,
    string propertyName,
    bool ascendingOrder)
{
    var propertyDescriptor = TypeDescriptor.GetProperties(typeof(T))
                                          .Find(propertyName, false);


        if (elements == null)
    if (propertyDescriptor == null)
         {
         throw new Exception($"Property '{propertyName}' not found.");
            throw new ArgumentNullException(nameof(elements));
        }


         foreach (var element in elements)
    return ascendingOrder ?
         {
         source.OrderBy(x => propertyDescriptor.GetValue(x)) :
            collection.Remove(element);
         source.OrderByDescending(x => propertyDescriptor.GetValue(x));
        }
}
    }
</filebox>


    public static void Remove<T>(this ICollection<T> collection, Func<T, bool> predicate)
== IListExtension ==
    {
<filebox fn='IListExtension.cs' collapsed>
        if (collection == null)
/// <summary>
        {
/// Groups items by range, allowing overlap.
            throw new ArgumentNullException(nameof(collection));
/// Groups by a range of 10 items. Group 1 will get items 0 to 10. Group 2 will get items 10 to 20.
        }
/// </summary>
public static IEnumerable<IReadOnlyCollection<T>> GroupByRange<T>(this List<T> source, int rangeSize)
{
  var result = new Dictionary<int, List<T>>();
  for (var i = 0; i < source.Count; i++)
  {
      var groupId = i / rangeSize;


        collection.RemoveEach(collection.Where(predicate));
      if (result.TryGetValue(groupId, out var list))
    }
          list.Add(source[i]);
      else
          result[groupId] = [source[i]];


    public static void RemoveSingle<T>(this ICollection<T> collection, Func<T, bool> predicate)
      if (i % rangeSize == 0 && i - 1 > 0)
    {
          result[groupId - 1].Add(source[i]);
        if (collection == null)
  }
        {
            throw new ArgumentNullException(nameof(collection));
        }


        collection.Remove(collection.Single(predicate));
  return result.Values.Select(x => x.AsReadOnly());
    }
}
}
</kode>
</filebox>

Dernière version du 1 novembre 2024 à 14:41

Disponible à partir de C# 3, elles permettent d'ajouter des méthodes à une classe ou à une structure sans en modifier son code.

  • Les méthodes doivent être déclarées dans une classe static.
  • Les méthodes qui étendent une classe ou une structure ne peuvent accéder qu’aux membres publics.
Cs.svg
// Déclaration de la méthode d'extension dans une classe static
public static class StringExtensions
{
    /// <summary>
    /// A Contains method with a comparison type.
    /// </summary>
    public static bool Contains(this string source, string value, StringComparison comparisonType)
    {
        return source.IndexOf(value, comparisonType) >= 0;
    }
}

// Utilisation de la méthode d'extension : comparaison de string en ignorant la casse
var monString = "ASTRINGTOTEST";
monString.Contains("string", StringComparison.OrdinalIgnoreCase);

Useful extension methods

CollectionExtension

CollectionExtension.cs
/// <summary>
/// Adds each item to the list.
/// </summary>
/// <remarks>
/// The <see cref="IList{T}" /> interface does not have AddRange in its contract, contrary to the <see cref="List{T}" /> implementation.
/// The latter uses an optimized routine for adding a range of elements, and naming this extension method AddRange too would give the wrong impression of performance.
/// Additionally, for collections that notify of their changes, AddRange reads as if there would be only one notification of change after all elements have been added, when in fact there would probably by as many notifications as items being added.
/// </remarks>
public static void AddEach<T>(this ICollection<T> collection, IEnumerable<T> elements)
{
    ArgumentNullException.ThrowIfNull(collection);
    ArgumentNullException.ThrowIfNull(elements);

    if (collection is List<T> list)
    {
        list.AddRange(elements);
    }
    else
    {
        foreach (var element in elements)
        {
            collection.Add(element);
        }
    }
}

/// <summary>
/// Removes each item from the list.
/// </summary>
/// <remarks>
/// This method is not named RemoveRange, because it does not have the same purpose as <see cref="List{T}.RemoveRange" />.
/// </remarks>
public static void RemoveEach<T>(this ICollection<T> collection, IEnumerable<T> elements)
{
    ArgumentNullException.ThrowIfNull(collection);
    ArgumentNullException.ThrowIfNull(elements);

    foreach (var element in elements)
    {
        collection.Remove(element);
    }
}

public static void Remove<T>(this ICollection<T> collection, Func<T, bool> predicate)
{
    ArgumentNullException.ThrowIfNull(collection);

    collection.RemoveEach(collection.Where(predicate));
}

public static void RemoveSingle<T>(this ICollection<T> collection, Func<T, bool> predicate)
{
    ArgumentNullException.ThrowIfNull(collection);

    collection.Remove(collection.Single(predicate));
}

IEnumerableExtension

IEnumerableExtension.cs
/// <summary>
/// Update the property value of the items of the collection.
/// </summary>
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
    foreach (T item in source)
        action(item);
}

public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
    foreach (T item in source)
    {
        action(item);
        yield return item;
    }
}

/// <summary>
/// Sorts the elements of a sequence according to an element's property.
/// </summary>
public static IEnumerable<T> OrderBy<T>(
    this IEnumerable<T> source,
    string propertyName,
    bool ascendingOrder)
{
    var propertyDescriptor = TypeDescriptor.GetProperties(typeof(T))
                                           .Find(propertyName, false);

    if (propertyDescriptor == null)
        throw new Exception($"Property '{propertyName}' not found.");

    return ascendingOrder ?
        source.OrderBy(x => propertyDescriptor.GetValue(x)) :
        source.OrderByDescending(x => propertyDescriptor.GetValue(x));
}

IListExtension

IListExtension.cs
/// <summary>
/// Groups items by range, allowing overlap.
/// Groups by a range of 10 items. Group 1 will get items 0 to 10. Group 2 will get items 10 to 20.
/// </summary>
public static IEnumerable<IReadOnlyCollection<T>> GroupByRange<T>(this List<T> source, int rangeSize)
{
   var result = new Dictionary<int, List<T>>();
   for (var i = 0; i < source.Count; i++)
   {
       var groupId = i / rangeSize;

       if (result.TryGetValue(groupId, out var list))
           list.Add(source[i]);
       else
           result[groupId] = [source[i]];

       if (i % rangeSize == 0 && i - 1 > 0)
           result[groupId - 1].Add(source[i]);
   }

   return result.Values.Select(x => x.AsReadOnly());
}