2009-06-02 10 views
3

est-il un bon générique, façon de faire ce qui suit sans avoir recours à une seconde méthode ou beaucoup de moulages - je veux garder l'API le plus léger possible et il me semble ok OO-sage:Surcharge d'interface générique pour les méthodes?

class Foo 
{ 
    public T Bar<T>() where T: IAlpha 
    { 
    /* blahblahblah */ 
    } 

    public T Bar<T>() where T: IBeta 
    { 
    /* blahblahblah */ 
    } 
} 

interface IAlpha 
{ 
    string x {set;} 
} 

interface IBeta 
{ 
    string y {set;} 
} 

merci

Répondre

7

Vous ne pouvez pas surcharger une méthode par valeur de retour uniquement (générique ou non). En outre, il serait impossible de résoudre les appels à Bar, car un objet pourrait implémenter à la fois IAlpha et IBeta, ce qui n'est pas possible en utilisant la surcharge.

public class AlphaBeta : IAlpha, IBeta 
{ 
    string x {set;} 
    string y {set;} 
} 

// too ambiguous 
AlphaBeta parkingLot = myFoo.Bar<AlphaBeta>(); 

Le ci-dessous ne fonctionne pas non plus, parce que les méthodes ne diffèrent que par le type de retour

class Gar 
{ 
    public string Foo() 
    { 
     return ""; 
    } 

    public int Foo() 
    { 
     return 0; 
    } 
} 

Malheureusement, la meilleure solution sera d'utiliser une solution moins générique. Le modèle de commande pourrait vous servir bien ici.

public class Foo 
{ 
    private readonly static Dictionary<Type, Command> factories = 
     new Dictionary<Type, Command>(); 

    static Foo() 
    { 
     factories.Add(typeof(IAlpha), new AlphaCreationCommand()); 
     factories.Add(typeof(IBeta), new BetaCreationCommand()); 
    } 

    public T Bar<T>() 
    { 
     if (factories.ContainsKey(typeof(T))) 
     { 
      return (T) factories[typeof(T)].Execute(); 
     } 
     throw new TypeNotSupportedException(typeof(T)); 
    } 
} 

// use it like this 
IAlpha alphaInstance = myFoo.Bar<IAlpha>(); 
IBeta betaInstance = myFoo.Bar<IBeta>(); 

Une autre façon de mettre en œuvre Bar qui vous permet d'appeler sans déclarer explicitement le type (dans vos supports coudés) est d'utiliser un paramètre out. Je l'éviterais, cependant, puisque les paramètres de 100% contrôlés sont habituellement mauvais.

public void Bar<T>(out T returnValue) 
{ 
    if (factories.ContainsKey(typeof(T))) 
    { 
     returnValue = (T) factories[typeof(T)].Execute(); 
     return; 
    } 
    throw new TypeNotSupportedException(typeof(T)); 
} 

// call it like this 
// T is inferred from the parameter type 
IAlpha alphaInstance; 
IBeta betaInstance; 
myFoo.Bar(out alphaInstance); 
myFoo.Bar(out betaInstance); 

J'exclus Command, AlphaCreationCommand, BetaCreationCommand et TypeNotSupportedException. Leur mise en œuvre devrait être assez explicite.

Alternativement, vous pouvez utiliser Func au lieu des commandes, mais cela vous oblige à implémenter tout votre code d'instanciation dans Foo qui peut devenir incontrôlable au fur et à mesure que votre base de code se développe.

+0

Il ne compilera pas spécifiquement pour les types qui implémentent les deux. Il * compilera * pour tous les autres types cependant (votre mot implique qu'il ne compilera pas, période, à cause de cela). –

+0

Je ne suis pas au courant de quand la surcharge de méthode par le type de retour compilera seulement. Si vous pouvez donner un exemple, je peux modifier ma réponse pour la corriger. –

1

Que pensez-vous de cela?

class Foo 
{ 
    public void Bar<T>(Action<T> @return) where T: IAlpha 
    { 
    @return(new AlphaImpl()); 
    } 

    public void Bar<T>(Action<T> @return) where T: IBeta 
    { 
    @return(new BetaImpl()); 
    } 
} 

interface IAlpha 
{ 
    string x {set;} 
} 

interface IBeta 
{ 
    string y {set;} 
}