2009-03-02 6 views
2

J'ai essayé de créer une classe de base simple qui encapsule certaines de mes conventions pour l'accès à la base de données. Je crée généralement un sproc nommé "products_retrieve_product" pour sélectionner un produit basé sur productID. Je voudrais que la méthode "Retrieve" dans la classe de base retourne le type que la classe dérivée fournit dans sa définition. Est ce que j'essaye d'accomplir possible avec des génériques?Comment retourner un type générique via une méthode dans une classe de base?

public class MyBaseClass <T> 
{ 
    private string _className; 

    public MyBaseClass() 
    { 
     _className = this.GetType().Name; 
    } 

    public virtual T Retrieve(int ID) 
    { 
     Database db = DatabaseFactory.CreateDatabase(); 
     DbCommand dbCommand = db.GetStoredProcCommand(String.Format("{0}s_Retrieve_{0}", _className)); 
     db.AddInParameter(dbCommand, String.Format("@{0}ID", _className), DbType.Int32, ID); 

     using (IDataReader dr = db.ExecuteReader(dbCommand)) 
     { 
      if (dr.Read()) 
      { 
       BOLoader.LoadDataToProps(this, dr); 
      } 
     } 
     return (T)this; 
    } 
} 

Répondre

2

Je pense que vous voulez faire quelque chose comme ceci:

class MyBaseClass<T> where T : MyBaseClass<T>, new() 
{ 
    public T Retrieve() 
    { 
     return new T(); 
    } 
} 

class Foo : MyBaseClass<Foo> 
{ 
} 

class Program 
{ 
    public static void Main() 
    { 
     Foo f = new Foo(); 
     Foo f2 = f.Retrieve(); 
     Console.WriteLine(f2.ToString()); 
    } 
} 

Lorsque vous exécuter ce programme, le nom de type de Foo est imprimé sur la ligne de commande. De toute évidence, il s'agit d'un exemple artificiel, mais peut-être que vous pouvez faire quelque chose de plus utile lors du chargement à partir d'une base de données dans MyBaseClass.Retrieve().

La clé consiste à ajouter une contrainte sur T afin qu'elle soit une instance de la classe elle-même. De cette façon, vous pouvez spécifier la sous-classe comme type générique lors du sous-classement MyBaseClass<T>.

Je ne suis pas entièrement sûr si c'est une bonne idée ou pas, mais il semble que cela puisse être fait.

-1

Non, ce n'est pas, parce que ce que vous avez vraiment besoin d'être en mesure de faire quelque chose comme ça dans la définition de classe:

public class MyBaseClass<T> : T 

Ce qui est actuellement impossible avec les génériques. Ce que vous devez faire est de séparer l'usine de ce que l'usine produit (vous avez besoin d'une classe séparée qui va construire T, et vous devez ensuite fournir des méthodes d'assistance pour travailler sur T, éventuellement des méthodes d'extension).

1

Bien sûr. Dans votre exemple, si je voulais que ma classe Foo pour retourner Bars quand Retrieve (...) est appelé:

public class Foo : MyBaseClass<Bar>{} 
+0

La partie que je suis coincé sur la façon dont la méthode est « Récupérer » jette l'objet dans le type dérivé. –

+0

Vous ne devriez pas avoir à le lancer du tout, puisqu'il est déjà déclaré comme le type de retour de la méthode: "return this;" fait le travail dont vous avez besoin. –

+0

Je pense que vous parlez de la méthode dans la classe dérivée, mais j'aimerais que la classe de base implémente une méthode qui renvoie un type basé sur la classe dérivée. –

0

Hmm, nous utilisons la réflexion pour obtenir le nom de classe. BOLoader utilise sans doute la réflexion pour charger certaines propriétés. Pourquoi ne pas s'engager pleinement dans la réflexion?

BOLoader ne se soucie pas de ce jeu de "type de retour". Pourquoi devrions nous?

public static class MyBaseClassExtender 
{ 
    public static void Retrieve(this MyBaseClass entity, int ID) 
    { 
     string className = entity.GetType().Name; 
     Database db = DatabaseFactory.CreateDatabase(); 
     DbCommand dbCommand = db.GetStoredProcCommand(String.Format("{0}s_Retrieve_{0}", className)); 
     db.AddInParameter(dbCommand, String.Format("@{0}ID", className), DbType.Int32, ID); 

     using (IDataReader dr = db.ExecuteReader(dbCommand)) 
     { 
      if (dr.Read()) 
      { 
       BOLoader.LoadDataToProps(this, dr); 
      } 
     } 
    } 
} 

Ensuite, vous dites simplement:

Foo myFoo = new Foo(); 
myFoo.Retrieve(2); 
Questions connexes