2012-07-11 12 views
18

Estoy jugando con genéricos e IEnumerable abit, pero estoy un poco atrapado. Esto es lo que estoy tratando de hacer: - (?) Quiero tener un método que devuelve cualquier tipo de colección que implementa IEnumerable - (así por ejemplo: Lista, pila, cola, ...)devolviendo un genérico IEnumerable <T>

además, Quiero poder devolver cualquier tipo de colección, de cualquier tipo de datos. así que quiero este método sea capaz de devolver un List<string>, así como un Stack<int>, así como un List<double> ... etc etc.

public IEnumerable<T> returnSomething() 
    { 
     Stack<int> stackOfInts = new Stack<int>(); 
     List<string> listOfStrings = new List<string>(); 
     return stackOfInts; 
    } 

esto es lo que he probado hasta ahora. Sin embargo, esto no funciona, me sale este error:

Cannot implicitly convert type 'System.Collections.Generic.Stack<int>' to 'System.Collections.Generic.IEnumerable<T>'. An explicit conversion exists (are you missing a cast?) 

sin embargo, si se sustituye la IEnumerable<T> en la firma del método a IEnumerable<int>, puedo devolver cualquier colección de tipo int. Sin embargo, esto significa que ahora ya no puedo devolver el ListOfStrings.

agradecería cualquier sugerencia o idea :)

Respuesta

26

es necesario agregar un generic type parameter a su método:

parámetro
public IEnumerable<T> ReturnSomething<T>() 
{ 
    Stack<T> stackOfT = new Stack<T>(); 
    return stackOfT; 
} 

El tipo aparece después del nombre del método, pero antes de los parámetros. También es posible tener un método con más de un parámetro de tipo.

Cuando se llama al método puede especificar el tipo:

IEnumerable<int> myInts = ReturnSomething<int>(); 
+0

gracias, esto funciona de hecho, pero ahora parece que no puede añadir cualquier cosa para la pila ... stackeffects.Push (3); si intento esto, dice: "la mejor coincidencia sobrecargada ... tiene algunos argumentos inválidos". ¿algunas ideas? – Thousand

+0

@JaneDoe: solo puede agregar 'T's a' Stack '. 3 no es necesariamente una 'T'. A menos que agregue una [restricción de tipo genérico] (http://msdn.microsoft.com/en-us/library/d5x73970.aspx) no tiene idea de qué es una 'T', por lo que ni siquiera puede construir una - para hacer eso, necesitarías una restricción 'new()'. ¿Qué estás tratando de hacer, y por qué lo necesitas? –

+1

No necesito esto para nada en particular, estoy probando un montón de cosas. Pero lo entiendo ahora, gracias. – Thousand

10

El truco es declarar<T> derecha, si se define genérica <T>, entonces usted tiene que atenerse a ella en sus métodos, por lo si tiene IEnumerable<T>, entonces, en cualquier otro lugar de su método, debe usar <T> y no <int> o cualquier otro tipo.

Es solo el último cuando realmente usa tipo genérico que sustituye <T> genérico por un tipo real.

ver una muestra

class Foo<T> 
{ 
    public IEnumerable<T> GetList() 
    { 
     return new List<T>(); 
    } 

    public IEnumerable<T> GetStack() 
    { 
     return new Stack<T>(); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Foo<int> foo = new Foo<int>(); 
     IEnumerable<int> list = foo.GetList(); 
     IEnumerable<int> stack = foo.GetStack(); 

     Foo<string> foo1 = new Foo<string>(); 
     IEnumerable<string> list1 = foo1.GetList(); 
     IEnumerable<string> stack1 = foo1.GetStack(); 
    } 
} 
1

sí se puede devolver cualquier tipo si cambia I Enumerable<T> to IEnumerable<dynamic>

así:

public IEnumerable<dynamic> returnSomething() 
{ 
..... 
+2

¿Por qué usar genéricos en absoluto si va a tirar el tipo de seguridad por la ventana? – Adam

+0

esto de hecho parece un poco de un truco ... Lo probé y tampoco compilé. – Thousand

+0

@codesparkle Estoy de acuerdo con su punto y sigo fuertemente también, pero en sus momentos en que no tiene control en el tipo de retorno de método de API de terceros dado, tan dinámico es el salvador en tal caso – HatSoft

2
public IEnumerable<T> returnSomething() 
{ 
    Stack<int> stackOfInts = new Stack<int>(); 
    return (IEnumerable<T>) stackOfInts; 
} 
1

El parámetro de tipo necesita ser especificado por la persona que llama en alguna parte.

ya sea cuando una instancia de una clase genérica:

public class MyClass<T> 
{ 
    public IEnumerable<T> returnSomething() 
    { 
     Stack<T> stackOfTs = new Stack<T>(); 
     List<T> listOfTs = new List<T>(); 
     return stackOfTs; 
    } 
} 

var v = new MyClass<int>(); 
foreach(var item in v.returnSomething()) 
{ 
} 

O cuando se llama a un método genérico de una clase no genérica:

public class MyClass 
{ 
    public IEnumerable<T> returnSomething<T>() 
    { 
     Stack<T> stackOfTs = new Stack<T>(); 
     List<T> listOfTs = new List<T>(); 
     return stackOfTs; 
    } 
} 


var v = new MyClass(); 
foreach(var item in v.returnSomething<int>()) 
{ 
} 
Cuestiones relacionadas