2009-11-24 7 views
8

Por lo tanto, estoy seguro de que esto ya se ha respondido en algún lugar, pero no lo pude encontrar en ningún lado. Esperando que algunos géneros genéricos puedan ayudar.Método genérico con acción <T> parámetro

public interface IAnimal{} 
public class Orangutan:IAnimal{} 

public void ValidateUsing<T>(Action<T> action) where T : IAnimal 
{ 
    Orangutan orangutan = new Orangutan(); 
    action(orangutan); //Compile error 1 

    //This doesn't work either: 
    IAnimal animal = new Orangutan(); 
    action(animal); //Compile error 2 
} 
  1. Tipo de argumento 'orangután' no no es asignable a parámetro de tipo 'T' tipo
  2. Argumento 'IAnimal' es asignable a parámetro de tipo 'T'

Editar: Based en Yuriy y otras sugerencias, podría hacer algo de fundición como:

public void ValidateUsing<T>(Action<T> action) where T : IAnimal 
{ 
    Orangutan orangutan = new Orangutan(); 
    action((T)(IAnimal)orangutan); 

    //This doesn't work either: 
    IAnimal animal = new Orangutan(); 
    action((T)animal); 
} 

Lo que quería hacer era llamar al método ValidateUsing así:

ValidateUsing(Foo); 

Por desgracia, si foo es el siguiente:

private void Foo(Orangutan obj) 
{ 
    //Do something 
} 

tengo que especificar explícitamente el tipo cuando llamo ValidateUsing

ValidateUsing<Orangutan>(Foo); 

Respuesta

6

¿Por qué instancias de un Orangutan si se supone que deben aceptar cualquier IAnimal?

public void ValidateUsing<T>(Action<T> action) where T : IAnimal, new() 
{ 
    T animal = new T(); 
    action(animal); //Compile error 2 

Si se vuelve a utilizar el parámetro genérico, que no tendrá ningún problema de tipo ...

Ahora, en cuanto a por qué su código no funciona, todo lo que está diciendo es que el tipo T derivará de IAnimal. Sin embargo, podría ser tan fácilmente Giraffe como Orangutan, por lo que no puede asignar Orangutan o IAnimal a un parámetro del tipo T.

+0

Gracias bdukes, acabo de utilizar el orangután como ejemplo. Probablemente uno malo. Quiero poder invocar la acción con cualquier IAnimal. En el código "real", el IAnimal se almacena como un campo privado en la clase. Entonces, realmente no estoy instanciando nada. –

2

Pruebe esto.

Orangutan orangutan = new Orangutan(); 
Action<IAnimal> castedAction = action as Action<IAnimal>; 
castedAction(orangutan); 
+0

Gracias Stan! Devolvería tu respuesta si tuviera suficiente reputación. –

2

realizar los siguientes cambios:

Orangutan orangutan = new Orangutan(); 
action((T)(IAnimal)orangutan); 


IAnimal animal = new Orangutan(); 
action((T)animal); 
+0

Hola Yuriy, esto funciona muy bien. Me lleva a una parte del camino (ver edición). ¡Gracias! –

0
public interface IAnimal { } 
public class Orangutan : IAnimal { } 

public void ValidateUsing<T>(Action<T> action) where T : IAnimal 
{ 
    Orangutan orangutan = new Orangutan(); 
    action((T)(orangutan as IAnimal)); // needs to be cast as IAnimal 

    //This doesn't work either: 
    IAnimal animal = new Orangutan(); 
    action((T)animal); // needs to be cast as T 
} 

También parece que el hecho de que se trata de una interfaz hace la diferencia. Si usted tenía una clase abstracta animal, en lugar de una interfaz, usted puede hacer esto:

public abstract class Animal { } 
public class Orangutan : Animal { } 

public void ValidateUsing<T>(Action<T> action) where T : Animal 
{ 
    Orangutan orangutan = new Orangutan(); 
    action(orangutan as T); 

    //This doesn't work either: 
    Animal animal = new Orangutan(); 
    action(animal as T); 
} 
+0

Hola, gracias por la respuesta detallada. Tiendo a usar interfaces mucho más a menudo que las clases abstractas (favor de composición vs. herencia y todo eso), pero es interesante saber que funciona con una clase abstracta. –

4

Lo que pasa es que T representa algún tipo que por cierto implementa IAnimal.

lo tanto, cuando intenta compilar action(new Organatum()) que conseguir un error, ya que han declarado que la acción debe tener un parámetro de tipo T que a su vez podría ser de tipo, digamos, Fish - no se puede echar Organatum a un Fish, ¿verdad?

Si desea desencadenar cualquier acción que adopte el parámetro de un tipo que implemente la interfaz IAnimal, simplemente olvídese de los genéricos y use Action<IAnimal>.

HTH.

Cuestiones relacionadas