Name for a Chainable FOREach [closed]

4

Linq ha un metodo Select , che prende un Func<TIn, TOut> e lo mappa su un iterabile.

Sto cercando di trovare un buon nome per un metodo che prende un Action <TIn> , lo trasforma per restituire il suo argomento e mappa quello su un iterabile.

Il metodo è

public static IEnumerable<T> MyMap<T>(this IEnumerable<T> source, Action<T> action)
{
    return source.Select(i => {action(i); return i;});
}

L'uso iniziale di questo sarebbe eventi vincolanti sugli oggetti:

Controls.AddRange(Enumerable.Range(1, 10).Select(n => new Button(){Text = n.ToString()}).MyMap(b => b.Click += NumberButton_Click).ToArray());

In C # 6, questo è ridondante poiché gli inizializzatori di oggetti possono associare eventi, ma sono bloccato in 5 (dove non è valido farlo) per il futuro prevedibile per ragioni aziendali.

Sono a conoscenza di List.ForEach , ma questo è un metodo void , voglio qualcosa che posso concatenare, come visto sopra.

Modifica: l'esempio di Button era solo un esempio di come lo userei.

Il codice in cui verrebbe usato è più vicino a

private void DoStuff(IEnumerable<Foo> foos)
{
    var fooList = foos.ToList();
    foreach (var foo in fooList)
    {
        Foo localFoo = foo;
        localFoo.ValueChanged += (sender, e) =>
            {
                var newArgs = new FooBarEventArgs(localFoo.Bar, e.Baz);
                this.OnFooBar(newArgs)
            };
    }

    _wrappedClass.DoStuff(fooList);
}

Quindi non ho il controllo sulla creazione di IEnumerable , e non c'è un singolo elemento equivalente a DoStuff . Tuttavia, con MyMap , diventa un pulitore (IMHO):

private void DoStuff(IEnumerable<Foo> foos)
{
    _wrappedClass.DoStuff(foos.MyMap(f => f.ValueChanged += (sender, e) => this.OnFooBar(new FooBarEventArgs(f.Bar, e.Baz)));
}
    
posta RoadieRich 06.05.2016 - 20:25
fonte

2 risposte

11

Le funzioni di Linq con effetti modificatori violeranno almeno il principio del minimo stupore, quindi quello che hai in mente è un odore di codice, per mia comprensione.

Per il tuo caso d'uso, penso che sia molto più leggibile quando non provi a spingere il maggior numero di comandi in una riga come puoi. Perché non scrivere una funzione come

IEnumerable<Button> CreateButtons()
{
     for(int n=0;i<10;++n)
     {
         var b = new Button();
         b.Text=n.ToString();
         b.Click += NumberButton_Click;
         yield return b;
     }
 }

Tuttavia, se vuoi comunque ottenere questo risultato con un'espressione Linq, prova

        Controls.AddRange(Enumerable.Range(1, 10).Select(
            n => {
                var b = new Button();
                b.Text = n.ToString();
                b.Click += NumberButton_Click;
                return b;
            }));

Prenderò in considerazione la possibilità di mettere la creazione del pulsante in una funzione con nome come CreateButton(int n) , questo ti lascia con

Controls.AddRange(Enumerable.Range(1, 10).Select( n => CreateButton(n)));

In questo modo, non è necessario inventare una puzzolente funzione MyMap .

Al tuo secondo esempio: IMHO la prima variante senza MyMap può essere resa più completa tralasciando le variabili locali non necessarie. Tuttavia, inserendo il gestore di eventi in un'espressione Select funziona in modo simile:

wrappedClass.DoStuff(foos.Select(f => 
   { 
       f.ValueChanged += 
             (sender, e) => this.OnFooBar(new FooBarEventArgs(f.Bar, e.Baz));
       return f;
   }));

Tuttavia questa è una soluzione con effetti collaterali. Per migliorare la leggibilità, perché non dare l'operazione che aggiunge un nome ai gestori?

IEnumerable<Foo> AddHandlers( IEnumerable<Foo> foos)
{
     foreach (f in foos)
     {
        f.ValueChanged += 
             (sender, e) => this.OnFooBar(new FooBarEventArgs(f.Bar, e.Baz));
        yield return f;
     }
 }
    
risposta data 06.05.2016 - 21:04
fonte
3

La libreria MoreLINQ ha questo metodo e la chiama Pipe , che trovo molto appropriata.

Pipe   |   Executes the given action on each element in the source sequence and yields it

Se sei interessato - puoi vedere il codice sorgente qui .

    
risposta data 16.05.2016 - 10:31
fonte

Leggi altre domande sui tag