2008-10-21 11 views
22

Je l'interface suivante:Lancer un objet à une interface générique

internal interface IRelativeTo<T> where T : IObject 
{ 
    T getRelativeTo(); 
    void setRelativeTo(T relativeTo); 
} 

et un tas de classes qui (devrait) mettre en œuvre, tels que:

public class AdminRateShift : IObject, IRelativeTo<AdminRateShift> 
{ 
    AdminRateShift getRelativeTo(); 
    void setRelativeTo(AdminRateShift shift); 
} 

Je me rends compte que ces trois ne sont pas les mêmes:

IRelativeTo<> 
IRelativeTo<AdminRateShift> 
IRelativeTo<IObject> 

mais néanmoins, je besoin d'un moyen de travailler avec toutes les différentes classes comme AdminRateShift (et FXRat eShift, DetRateShift) qui devrait tous implémenter IRelativeTo. Disons que j'ai une fonction qui retourne AdminRateShift comme objet:

IRelativeTo<IObject> = getObjectThatImplementsRelativeTo(); // returns Object 

Par programmation sur l'interface, je peux faire ce que je dois, mais je ne peux pas vraiment jeter l'objet à IRelativeTo je peux l'utiliser .

C'est un exemple trivial, mais j'espère que cela clarifiera ce que j'essaie de faire.

Répondre

22

Si je comprends bien la question, l'approche la plus commune serait de déclarer une base interface non générique, à savoir

internal interface IRelativeTo 
{ 
    object getRelativeTo(); // or maybe something else non-generic 
    void setRelativeTo(object relativeTo); 
} 
internal interface IRelativeTo<T> : IRelativeTo 
    where T : IObject 
{ 
    new T getRelativeTo(); 
    new void setRelativeTo(T relativeTo); 
} 

Une autre option est pour vous codez en grande partie dans les génériques ... vous dire ont des méthodes telles que

void DoSomething<T>() where T : IObject 
{ 
    IRelativeTo<IObject> foo = // etc 
} 

Si le IRelativeTo<T> est un argument DoSomething(), alors habituellement vous n'avez pas besoin de spécifier l'argument de type générique vous-même - le compilateur inférer - à savoir

DoSomething(foo); 

plutôt que

DoSomething<SomeType>(foo); 

Il y a des avantages pour les deux approches.

+4

Salut, j'ai fait la première méthode que vous avez décrite. Y a-t-il un moyen de rendre une classe héritière de 'IRelativeTo 'de ne pas avoir à implémenter' IRelativeTo' aussi? –

+0

@dav_i si vous gardez les deux interfaces, alors non –

+0

Dommage, vous vous attendez à ce que le mot clé 'new' le cache vraiment. Bien que je devine alors si vous jetez votre objet au non-générique vous ne sauriez pas quoi faire ... Merci! –

11

Malheureusement, l'héritage ne fonctionne pas avec les génériques. Si votre fonction attend IRelativeTo, vous pouvez rendre la fonction générique ainsi:

void MyFunction<T>(IRelativeTo<T> sth) where T : IObject 
{} 

Si je me souviens bien, lorsque vous utilisez la fonction ci-dessus vous ne même pas besoin de spécifier le type, le compilateur doit le comprendre basé sur l'argument que vous fournissez.

Si vous souhaitez conserver une référence à l'un de ces objets IRelativeTo à l'intérieur d'une classe ou d'une méthode (et vous ne vous souciez pas de ce qu'est T), vous devez rendre cette classe/méthode générique.

Je suis d'accord, c'est un peu douloureux.

5

Si tout ce que vous aimez est que les accords IRelativeTo avec IObjects vous n'avez pas besoin de le rendre générique:

interface IRelativeTo 
{ 
    IObject getRelativeTo(); 
    void setRelativeTo(IObject relativeTo) 
} 

Les cours d'exécution mais peuvent encore être générique,:

abstract class RelativeTo<T> : IRelativeTo where T : IObject 
{ 
    public virtual T getRelativeTo() {return default(T);} 

    public virtual void setRelativeTo(T relativeTo) {} 

    IObject IRelativeTo.getRelativeTo() {return this.getRelativeTo(); } 

    void IRelativeTo.setRelativeTo(IObject relativeTo) 
    { this.setRelativeTo((T) relativeTo); 
    } 
} 

class AdminRateShift : RelativeTo<AdminRateShift>, IObject {} 

Alors vous pouvez faire ceci:

IRelativeTo irt = new AdminRateShift(); 
    IObject o = irt.getRelativeTo(); 
    irt.setRelativeTo(o); 
Questions connexes