2009-10-22 11 views
0

Qu'est-ce que j'ai?C# Problème avec les génériques

J'ai une classe abstraite, QueryExecutor et une classe dérivée, SqlQueryExecutor montrée ci-dessous.

abstract class QueryExecutor<T> 
{ 
    public abstract T Execute(); 
} 

class SqlQueryExecutor<T> : QueryExecutor<T> where T:ICollection 
{ 
    public override T Execute() 
    { 
     Type type = typeof(T); 

     // Do common stuff 
     if (type == typeof(ProfileNodeCollection)) 
     { 
      ProfileNodeCollection nodes = new ProfileNodeCollection(); 
      // Logic to build nodes 
      return (T)nodes; 
     } 
     else 
     { 
      TreeNodeCollection nodes = new TreeNodeCollection(); 
      Logic to build nodes 

      return (T)nodes;     
     } 
    } 
} 

Qu'est-ce que je veux faire?

Dans la mise en œuvre de la méthode Execute(), je souhaite construire l'objet ICollection approprié et le renvoyer.

À quel problème suis-je confronté?

Dans la méthode Execute(), la ligne, return (T)nodes; montre l'erreur de compilation suivante:

Cannot convert type 'WebAppTest.ProfileNodeCollection' to 'T'

Toute idée comment puis-je résoudre ce problème?

Merci d'avance!

+0

vous avez déjà posé cette question il y a une heure: conception problème - classe de base commune et les différents types de retour: http://stackoverflow.com/questions/1605659/design-problem-common-base-class-and- different-return-types –

+4

Je ne suis pas sûr de savoir pourquoi le problème se pose, mais c'est un tel abus de génériques que je ne veux pas répondre de toute façon ... Le but des génériques est qu'ils doivent être * génériques * et ne devrait pas contenir de comportement spécial pour différents types concrets de 'T' (voir le principe de substitution de Liskov pour plus de détails). Si vous faites ce genre de chose, vous feriez mieux d'utiliser 'ProfileNodeCollectionQueryExecutor' et' TreeNodeCollectionQueryExecutor' comme des classes séparées (c'est-à-dire si votre situation nécessite un polymorphisme, alors utilisez-la). –

+0

@ Mitch Blé: J'ai essayé d'implémenter la réponse à la question précédente et j'ai été frappé ici. Pensé de mettre à jour la même question mais, je l'avais marqué comme répondu. Donc, créé une autre question. Cependant, cette question concerne la mise en œuvre de la partie précédente. – Vijay

Répondre

4

Eh bien, une façon simple de le fixer est de simplement faire le compilateur moins au courant de ce qui se passe, de sorte que ça va juste reporter au CLR:

return (T)(object)nodes; 

Vous pouvez mettre ce dans un seul endroit et utiliser une conversion implicite object en mission:

object ret; 
// Do common stuff 
if (type == typeof(ProfileNodeCollection)) 
{ 
    ProfileNodeCollection nodes = new ProfileNodeCollection(); 
    // Logic to build nodes 
    ret = nodes; 
} 
else 
{ 
    TreeNodeCollection nodes = new TreeNodeCollection(); 
    Logic to build nodes 

    ret = nodes; 
} 
return (T)ret; 

il est pas très agréable, mais il devrait fonctionner. Il serait probablement plus agréable de créer des classes dérivées séparées pour différents types de collections, en mettant éventuellement du code commun dans une classe de base abstraite.

1

Je choisirais de séparer les préoccupations ici. Vous pourriez même avoir une usine QueryExecutor qui fournirait le droit QueryExecutor en fonction du type de collection.

class ProfileSqlQueryExecutor : QueryExecutor<ProfileNodeCollection> 
{ 
    public override ProfileNodeCollection Execute() 
    { 
     ProfileNodeCollection nodes = new ProfileNodeCollection(); 
     // Logic to build nodes 
     return nodes; 
    } 
} 

class TreeSqlQueryExecutor : QueryExecutor<TreeNodeCollection> 
{ 
    public override TreeNodeCollection Execute() 
    { 
     TreeNodeCollection nodes = new TreeNodeCollection(); 
     Logic to build nodes 
     return nodes;     
    } 
} 
Questions connexes