2015-01-27 16 views
15

Diciamo che ho scritto il mio metodo per invertire la lista.È possibile applicare un metodo generico a un elenco di elementi?

public static void MyReverse<T>(List<T> source) 
{ 
    var length = source.Count; 
    var hLength = length/2; 
    for (var i = 0; i < hLength; i++) 
    { 
     T temp = source[i]; 
     source[i] = source[length - 1 - i]; 
     source[length - 1 - i] = temp; 
    } 
} 

Lo chiamo così e funziona.

var fooList = new List<Foo>(); 
MyReverse(fooList); 

Se voglio invertire più elenchi, lo chiamo così.

var fooList = new List<Foo>(); 
var barList = new List<Bar>(); 
var bazList = new List<Baz>(); 
MyReverse(fooList); 
MyReverse(barList); 
MyReverse(bazList); 

Se voglio invertire un numero arbitrario di liste, mi piacerebbe provare:

public static void Main(string[] args) 
{ 
    var lists = new List<object> 
    { 
     new List<Foo>(), 
     new List<Bar>(), 
     new List<Bar>() 
    }; 

    ReverseLists(lists); 
} 

public static void ReverseLists(List<object> sourceLists) 
{ 
    foreach (var sourceList in sourceLists) 
    { 
     MyReverse(sourceList); // Error: Type arguments cannot be inferred from usage 
    } 
} 

Ma questo genera un errore di compilazione. È ciò che sto cercando di fare possibile: potrebbe essere implementato il metodo ReverseLists?

+0

'sourceList' è' oggetto'. – leppie

+0

@Rik: Chiaramente non renderà felice il compilatore ... – leppie

+1

Se * veramente * ti serve, provalo con 'Elenco ' come tipo di parametro di 'ReverseLists'. – Ani

risposta

10

Supponendo di avere un metodo statico come questo

public static class ReverseHelper 
{ 
    public static void MyReverse<T>(IList<T> source) 
    { 
     var length = source.Count; 
     var hLength = length/2; 
     for (var i = 0; i < hLength; i++) 
     { 
      T temp = source[i]; 
      source[i] = source[length - 1 - i]; 
      source[length - 1 - i] = temp; 
     } 
    } 
} 

Con l'aiuto di un'interfaccia non generica e una classe generica si può fare.

public interface IReverser 
{ 
    void Reverse(); 
} 
public class ListReverser<T> : IReverser 
{ 
    private readonly IList<T> source; 
    public ListReverser(IList<T> source) 
    { 
     this.source = source; 
    } 
    public void Reverse() 
    { 
     ReverseHelper.MyReverse<T>(source); 
    } 
} 
static void Main(string[] args) 
{ 
    var lists = new List<IReverser> 
    { 
     new ListReverser<Foo>(new List<Foo>()), 
     new ListReverser<Bar>(new List<Bar>()), 
     new ListReverser<Bar>(new List<Bar>()) 
    }; 

    foreach (var reverser in lists) 
    { 
     reverser.Reverse(); 
    } 
} 

Ho usato IList<T> al contrario di List<T> per supportare più ampio numero di tipi; Se vuoi List<T> puoi rimetterlo.

+1

IMO questa è l'opzione più accurata. – Jamiec

2

Se si modificano le ReverseLists firma del metodo per

public static void ReverseLists<T>(IEnumerable<object> sourceLists) 
{ 
    foreach (var sourceList in sourceLists.OfType<List<T>>()) 
    { 
     MyReverse(sourceList); 
    } 
} 

Poi si può chiamare questo per ogni tipo di elenco:

ReverseLists<Foo>(lists); 
ReverseLists<Bar>(lists); 

Forse non è l'ideale dover chiamare una volta per tipo di elenco, ma un modifica relativamente piccola al codice esistente.

+0

@Nathan: Ah - ora ho capito: chiamate 'ReverseLists ' sullo stesso elenco per tutti i tipi possibili e ogni "esecuzione" di quel tipo è invertita. Che * avrebbe * funzionato, ma avresti bisogno di eseguirlo per ogni tipo: cosa succede se ci sono molti tipi diversi nell'elenco non solo 2 - lì comincerebbe a diventare disordinato ... – ChrFin

+0

@ChrFin - come per il mio ultimo riga nel testo della risposta :) – Nathan

7

Come per il mio commento sopra ...

il compilatore non può occulta dedurre il tipo di T quando passò object (che è effettivamente quello che sta succedendo)

Tuttavia, v'è una scelta molto più semplice - che è quello di basta abbandonare utilizzando farmaci generici, e cambiare la firma del metodo MyReverse a public static void MyReverse(IList source) (e altrove sostituire List<object> con IList)

cioè:

public static void Main(string args[]) 
{ 
    var lists = new List<IList> 
    { 
     new List<Foo>(), 
     new List<Bar>(), 
     new List<Bar>() 
    }; 

    ReverseLists(lists); 
} 

public static void MyReverse(IList source) 
{ 
    var length = source.Count; 
    var hLength = length/2; 
    for (var i = 0; i < hLength; i++) 
    { 
     var temp = source[i]; 
     source[i] = source[length - 1 - i]; 
     source[length - 1 - i] = temp; 
    } 
} 

public static void ReverseLists(List<IList> sourceLists) 
{ 
    foreach (var sourceList in sourceLists) 
    { 
     MyReverse(sourceList); // Error: Type arguments cannot be inferred from usage 
    } 
} 
public class Foo 
{ 
} 
public class Bar 
{ 
} 
+1

Ho appena iniziato a scrivere questo. Sono contento che tu mi abbia battuto. Questo mi ha insegnato che 'IList' non è solo un residuo dei giorni pre-generici. – Rawling

+2

Ciò introdurrà il pugilato e il disimballaggio non necessari in caso di tipi di valore. –

2

Per complimentarmi con la risposta di Sriram Sakthivel, la chiave del tuo problema è che il Tipo non può essere dedotto da quello che stai passando.Vale la pena notare che List<T> implementa IList in modo che il problema di cui sopra può essere riformulato utilizzando una matrice di parametri di lista come:

void Main() 
{ 
    var fooList = new List<string>(); 
    var barList = new List<string>(); 
    var bazList = new List<string>(); 
    ReverseLists(fooList, barList, bazList); 
} 

public static void ReverseLists(params IList [] sourceLists) 
{ 
    foreach (var sourceList in sourceLists) 
    { 
     MyReverse(sourceList); 
    } 
} 

public static void MyReverse(IList source) 
{ 
    var length = source.Count; 
    var hLength = length/2; 
    for (var i = 0; i < hLength; i++) 
    { 
     var temp = source[i]; 
     source[i] = source[length - 1 - i]; 
     source[length - 1 - i] = temp; 
    } 
} 
0

cambiamento di questa linea nel post originale:

MyReverse(sourceList); // Error: Type arguments cannot be inferred from usage 

a questo:

MyReverse(((System.Collections.IList)sourceList).Cast<object>().ToList()); 
Problemi correlati