Iterazione e azione ricorsiva su una collection gerarchica

Da una richiesta sul news group di ASP.NET riporto questi due extension method che ho scritto per iterare ricorsivamente su una collection in modo gerarchico ed effettuare un’azione, nel caso specifico è stato chiesto come cancellare tutte le TextBox di una pagina senza doverlo fare manualmente su ognuna:
-------------------------------------------------------- 
public static class ControlExtension
{
    public static void DoActionForAllChildren<T>(this Control container, Action<T> action)
    {
        container.Controls
            .OfType<Control>()
            .Traverse(control => control.Controls.OfType<Control>())
            .Where(control => control.GetType() == typeof(T))
            .Cast<T>()
            .ForEach(action);
    }
}

public static class EnumerableHierarchicalExtension
{
    public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> recursion)
    {
        foreach (T item in source)
        {

            yield return item;

            IEnumerable<T> recursionSequence = recursion(item);

            if (recursionSequence != null)
            {

                foreach (T itemRecurse in Traverse(recursionSequence, recursion))
                {

                    yield return itemRecurse;
                }
            }
        }
    }

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

Quindi la chiamata diventa:
--------------------------------------------------------
this.DoActionForAllChildren<TextBox>(action => action.Text = string.Empty);
--------------------------------------------------------

[Update]
Codice leggermente riadattato secondo il consiglio di Stefano.

Matteo Migliore.

Comments

# re: Iterazione e azione ricorsiva su una collection gerarchica
Gravatar Bello! Espressivo e generico...ma visto che c'eri potevi aggiungere anche un foreach per IEnumerable<T> cosi risparmiavi un ToList() che rovina "the beauty of lazy evaluation" :)

public static void ForEach<T>(
this IEnumerable<T> source,
Action<T> func)
{
foreach (var item in source)
func(item);
}
Left by Stefano Martinz on 6/13/2009 11:19 AM
# re: Iterazione e azione ricorsiva su una collection gerarchica
Gravatar Matteo, scusa per essere pignolo, ma quella sequenza .OfType().Traverse().Where().Cast() per quanto espressiva mi e' sembrata da subito un po' "troppo"...
Ho pensato: alla fine quello che si vuole fare qui è: eseguire un'Action su tutti i controlli di un certo tipo presenti in un data gerarchia. Quindi, quello che manca è un metodo OfTypeRecursive<T> su ControlCollection.

public static class ControlCollectionExtensions
{
public static IEnumerable<T> OfTypeRecursive<T>(this ControlCollection source) where T : Control
{
foreach (Control child in source)
{
T childAsT = child as T;
if (childAsT != null)
yield return childAsT;

foreach (var grandChild in child.Controls.OfTypeRecursive<T>())
yield return grandChild;
}
}
}

da cui la chiamata diventa:

this.Controls
.OfTypeRecursive<TextBox>()
.ForEach(action => action.Text = string.Empty);


Intendiamoci, il tuo metodo Traverse è più generico del mio quindi può certamente tornare utile in altre situazioni.
Left by Stefano Martinz on 6/14/2009 3:55 AM
# re: Iterazione e azione ricorsiva su una collection gerarchica
Gravatar Infatti, questa volta lo lascio così :-), il metodo Traverse è generico, lo lascio così. Ma grazie.
Left by Matteo Migliore on 6/14/2009 7:50 AM
Comments have been closed on this topic.