2009-11-24 11 views
8

Also, ich bin sicher, dass dies irgendwo da draußen zuvor beantwortet wurde, aber ich konnte es nirgendwo finden. Hoffe, dass einige Generika Guru helfen können.Generische Methode mit Aktion <T> Parameter

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. Argument Typ 'Orangutan' ist nicht belegbar Typ 'T'
  2. Argument Typ 'IAnimal' zuordenbar ist in den Parameter nicht Typ

Edit 'T' für den Parameter: Based auf Yuriy und andere Vorschläge, könnte ich einige Gießen wie:

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

Das, was ich rufen Sie tun wollte, war die ValidateUsing Methode wie folgt:

ValidateUsing(Foo); 

Leider, wenn foo wie folgt aussieht:

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

Ich muss ausdrücklich auf die Art angeben, wenn ich rufe ValidateUsing

ValidateUsing<Orangutan>(Foo); 

Antwort

6

Warum Sie eine Orangutan sind Instanziierung, wenn Sie sollen jede IAnimal akzeptieren werden?

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

Wenn Sie Ihre generischen Parameter wiederverwenden, werden Sie keine Probleme haben, Typen ...

nun in Bezug auf, warum Ihr Code funktioniert nicht, alles, was Sie sagen, ist, dass der Typ T wird von IAnimal abgeleitet. Es könnte jedoch genauso einfach eine Giraffe als Orangutan sein, so dass Sie nicht einfach einen Orangutan oder IAnimal einem Parameter des Typs T zuweisen können.

+0

Danke bdukes, ich habe gerade Orangutan als Beispiel benutzt. Wahrscheinlich ein schlechter. Ich möchte die Aktion mit jedem IAnimal aufrufen können. Im "echten" Code wird das IAnimal als privates Feld in der Klasse gespeichert. Also, ich bin nicht wirklich instanziiert irgendetwas. –

2

Versuchen Sie es.

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

Danke Stan! Ich würde deine Antwort auffrischen, wenn ich genug Ansehen hätte. –

2

die folgenden Änderungen:

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


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

Hi Yuriy, das funktioniert sehr gut. Es ist Teil des Weges (siehe Bearbeiten). Vielen Dank! –

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 
} 

Es scheint auch wie die Tatsache, dass es eine Schnittstelle ist, einen Unterschied macht. Wenn Sie eine abstrakte Klasse Tier hatte, statt eine Schnittstelle, können Sie dies tun:

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

Hallo Climbing, danke für die ausführliche Antwort. Ich neige dazu, Interfaces viel häufiger zu benutzen als abstrakte Klassen (favoriere Komposition gegen Vererbung und all das), aber es ist interessant zu wissen, dass es mit einer abstrakten Klasse funktioniert. –

4

Die Sache ist, dass T einige Typ darstellt, die durch die Art und Weise IAnimal implementiert.

Also, wenn Sie versuchen, action(new Organatum()) zu kompilieren Sie einen Fehler bekommen, weil Sie haben erklärt, dass die Aktion einen Parameter des Typs nehmen sollte T, der wiederum vom Typ sein könnte, sagen wir mal, Fish - Sie nicht Organatum werfen können zu einem Fish, können Sie?

Wenn Sie eine Aktion auslösen möchten, die Parameter eines Typs verwendet, der IAnimal Schnittstelle implementiert, dann vergessen Sie einfach Generics und verwenden Sie Action<IAnimal>.

HTH.

Verwandte Themen