2009-11-24 3 views
8

Donc, je suis sûr que cela a déjà été répondu quelque part auparavant, mais je ne l'ai trouvé nulle part. En espérant que certains génériques puissent aider.Méthode générique avec Action <T> Paramètre

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. Type d'argument 'Orangutan' est incessible au type de paramètre
  2. Argument type 'T' 'IAnimal' est incessible au paramètre type 'T'

Edit: Based Sur Yuriy et d'autres suggestions, je pourrais faire une certaine coulée telle que:

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); 
} 

La chose que je voulais faire était d'appeler la méthode ValidateUsing comme ceci:

ValidateUsing(Foo); 

Malheureusement, si foo ressemble à ceci:

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

Je dois préciser explicitement le type quand j'appelle ValidateUsing

ValidateUsing<Orangutan>(Foo); 

Répondre

6

Pourquoi êtes-vous instanciation d'un Orangutan si vous êtes censé être accepter tout IAnimal?

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

Si vous réutilisez votre paramètre générique, vous n'aurez pas de problèmes de type ...

Maintenant, en ce qui concerne les raisons pour lesquelles votre code ne fonctionne pas, tout ce que vous dites est que le type T dérivera de IAnimal. Cependant, il peut tout aussi bien être un Giraffe qu'un Orangutan, donc vous ne pouvez pas simplement affecter un Orangutan ou IAnimal à un paramètre de type T.

+0

Merci bdukes, je viens d'utiliser Orangutan comme exemple. Probablement un mauvais. Je veux être capable d'appeler l'action avec n'importe quel IAnimal. Dans le code "réel", IAnimal est stocké comme un champ privé dans la classe. Donc, je n'instance vraiment rien. –

2

Essayez ceci.

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

Merci Stan! Je reverrais votre réponse si j'avais assez de réputation. –

2

Effectuez les modifications suivantes:

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


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

Salut Yuriy, cela fonctionne très bien. Cela me fait partie du chemin (voir edit). Merci! –

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 
} 

Il semble également que le fait que ce soit une interface fasse la différence. Si vous aviez un animal de classe abstraite, au lieu d'une interface, vous pouvez le faire:

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

Hi climbage, merci pour la réponse détaillée. J'ai tendance à utiliser les interfaces beaucoup plus souvent que les classes abstraites (favoriser la composition contre l'héritage et tout ça), mais il est intéressant de savoir que cela fonctionne avec une classe abstraite. –

4

La chose est que T représente un certain type qui, par la façon dont IAnimal met en œuvre.

Ainsi, lorsque vous essayez de compiler action(new Organatum()) vous faire une erreur parce que vous avez déclaré que l'action devrait prendre un paramètre de type T qui pourrait à son tour être de type, disons, Fish - vous ne pouvez pas lancer Organatum à un Fish, pouvez-vous?

Si vous voulez déclencher une action qui prend un paramètre d'un type qui implémente l'interface IAnimal, alors oubliez simplement les génériques et utilisez Action<IAnimal>.

HTH.