Esistono buone risorse per il refactoring del codice C # esistente per l'uso di LINQ mantenendo i test in corso?

0

Mi sono insegnato un po 'di LINQ e un esercizio che pensavo sarebbe stato utile per prendere il mio codice Project Euler C # esistente, che ho creato utilizzando Test Driven Development e convertendolo gradualmente in LINQ. Mi rendo conto che LINQ non è sempre la soluzione migliore per tutti i problemi di Project Euler, ma non voglio approfondire qui.

Mi chiedo se sia possibile o meno rifattorizzare il codice "tradizionale" OO C # per utilizzare LINQ e la sintassi della programmazione funzionale, mantenendo il passaggio di tutti i test. Non riesco a trovare un modo per fare i piccoli passi che sono abituato a fare usando TDD durante la conversione in LINQ e questo è un ostacolo per me. Mi sembra di dover apportare grandi cambiamenti per trovare una singola funzione che poi sostituisca interi pezzi del mio codice con.

Mi rendo conto che potrei scrivere questo da zero in LINQ, ma nel mondo reale, mi piacerebbe essere in grado di sostituire parti del mio codice C # esistente per trarre vantaggio da LINQ dove appropriato.

Qualcuno ha avuto successo con questo approccio? Quali risorse hai trovato utili per il refactoring del codice C # esistente per utilizzare LINQ mentre adottassi un approccio di Test Driven Development?

    
posta Paddyslacker 30.06.2011 - 00:16
fonte

3 risposte

4

Se la tua implementazione può essere espressa come una serie di trasformazioni su elenchi di oggetti, allora questo dovrebbe essere abbastanza facile da fare a pezzetti, se è interamente dipendente dal mantenimento dello stato, allora non sarà facile.

Questa è una dichiarazione ottusa. Lasciatemi spiegare. Se hai un codice simile a questo:

var multiples = new List<int>()
for(var i=0;i<1000;i++)
  if(i%3==0 || i%5==0)
    multiples.Add(i);

var sum = 0;
foreach(var m in multiples)
  sum += m;

Questo è espressivo come tre operazioni distinte basate su set

  1. Genera tutti i numeri compresi tra 0 e 1000 (questo viene fatto implicitamente in questo caso dal ciclo for, ma puoi immaginare di avere un ciclo for per riempire un array che poi iterate per ottenere i multipli)
  2. Filtra solo quelli multipli di 3 o 5
  3. Aggrega quelli aggiungendo

In realtà potresti refactoring in 3 metodi che sembravano approssimativamente così e corrisponderebbero approssimativamente ai metodi Linq Enumerable.Range() , enumerableInstance.Where() e enumerableInstance.Aggregate() . Quindi sì, puoi farlo lì.

Se tuttavia la tua implementazione è la seguente:

var sum = 0;
for(var i=0;i<1000;i++)
  if(i%3==0 || i%5==0)
    sum += i;

Saresti più difficile vedere le operazioni di set e quindi essere in grado di suddividerle.

Vado avanti e dico, se puoi rifattorizzare la tua implementazione su una serie di metodi statici che non dipendono da alcuna variabile statica e prendi come input solo enumerazioni immutabili ( IEnumerable<T> o matrici) o lambdas / delegati e restituiscono solo enumerazioni, quindi la conversione di ogni pezzo singolarmente in LINQ dovrebbe essere facile come torta. Altrimenti, non lo sarà perché si tratta di un paradigma diverso, quello di filtrare le raccolte anziché lo stato di gestione in modo esplicito.

Inoltre, come dici tu, in molti casi la roba di Project Euler non funzionerà in modo efficiente con LINQ-to-objects, in questo modo dovresti cercare di usare le estensioni PLINQ che possono parallelizzare la tua query. Questo non è ancora lo stesso di un vero linguaggio funzionale che dovrebbe anche analizzare l'albero delle espressioni e fondamentalmente compilare le tue dichiarazioni con codice procedurale efficiente, ma è molto più vicino.

    
risposta data 30.06.2011 - 00:50
fonte
3

Ho utilizzato ReSharper di recente e ha auto-refactoring di foreach loop in linq dichiarazioni. Puoi provarlo gratuitamente e vedere se funziona per te.

    
risposta data 30.06.2011 - 06:08
fonte
2

Tipicamente un problema di Project Euler ruota intorno a un singolo algoritmo o catena di algoritmi (almeno quelli che ho fatto sono stati). Se i tuoi test unitari stanno testando il comportamento osservabile piuttosto che l'implementazione, non devi assolutamente (e in effetti non vuoi) toccare i test. Ad esempio, se hai implementato un setaccio primario i tuoi casi di test non dovrebbero preoccuparti se la tua implementazione è OO o funzionale - l'output sarà lo stesso.

Se sei davvero preoccupato di aver dimenticato i casi limite durante la scrittura dei test originali, potresti guardare qualcosa come Pex che può analizzare il codice e produrre casi che coprono tutti i possibili percorsi di codice.

    
risposta data 30.06.2011 - 00:28
fonte

Leggi altre domande sui tag