2010-09-17 2 views
0

J'essaye de créer une classe qui emploie une usine pour trouver la bonne classe et appelle ensuite des méthodes sur cette classe. Je fais quelque chose de mal cependant parce que l'intellisense dans Visual Studio m'avertit toujours des erreurs et quand j'essaie d'accéder aux méthodes qui devraient être dans la classe, les retours d'usine ne sont pas disponibles.Générique Factory pour les cours?

Quelqu'un peut-il me dire ce que je fais mal?

Voici le code où je suis en train d'obtenir une référence à la classe:

DBBase dal = DALFactory.GetDAL(typeof(T)); 

      myCollection = dal.GetByCriteria(myCriteria, sortExpression, startRowIndex, maximumRows, propertyNamesToBypassInstantiation); 

Voici le code pour la classe DALFactory:

internal static class DALFactory 
    { 
     // GetParser 
     internal static DBBase GetDAL(System.Type BOType) 
     { 
      switch (BOType.Name) 
      { 
       case "Person": 
        return new PersonDB(); 
} 
      // if we reach this point then we failed to find a matching type. Throw 
      // an exception. 
      throw new Exception("Unknown Type"); 
     } 
} 

Voici une partie du code la base de la classe retournée par la classe de l'usine:

public abstract class DBBase 
{ 
    protected static T GetSingleBO<T>(ref SqlCommand command) where T : BOBase 
    { 
     return GetSingleBO<T>(ref command, null); 
    } 


    protected static T GetSingleBO<T>(ref SqlCommand command, List<string> propertyNamesToBypassInstantiation) where T : BOBase 
    { 
     T BO = default(T); 
     try 
     { 
      command.Connection.Open(); 
      SqlDataReader reader = command.ExecuteReader(); 
      if (reader.HasRows) 
      { 
       reader.Read(); 
       BOParser parser = BOParserFactory.GetParser(typeof(T)); 
       parser.PopulateOrdinals(reader); 
       if (propertyNamesToBypassInstantiation == null) 
       { 
        BO = (T)parser.PopulateBO(reader); 
       } 
       else 
       { 
        BO = (T)parser.PopulateBO(reader, propertyNamesToBypassInstantiation); 
       } 
       reader.Close(); 
      } 
      else 
      { 
       // Whever there's no data, we return null. 
       BO = default(T); 
      } 
     } 
     catch (Exception ex) 
     { 
      StringBuilder sb = new StringBuilder(); 
      sb.AppendFormat("Error populating data: {0}", ex.Message); 
      if (ex.InnerException != null) 
      { 
       sb.AppendFormat(" -- Inner Exception: {0}", ex.InnerException.Message); 
      } 
      throw new Exception(sb.ToString(), ex); 
     } 
     finally 
     { 
      command.Connection.Close(); 
      command.Connection.Dispose(); 
     } 

     // return the BO, it's either populated with data or null. 
     return BO; 
    } 


    protected static EquatableList<T> GetBOEquatableList<T>(ref SqlCommand command) where T : BOBase 
    { 
     return GetBOEquatableList<T>(ref command, null); 
    } 

    protected static EquatableList<T> GetBOEquatableList<T>(ref SqlCommand command, List<string> propertyNamesToBypassInstantiation) where T : BOBase 
    { 
     EquatableList<T> BOList = new EquatableList<T>(); 
     try 
     { 
      command.Connection.Open(); 
      SqlDataReader reader = command.ExecuteReader(); 
      if (reader.HasRows) 
      { 
       // Get a parser for this BO type and populate 
       // the ordinals. 
       BOParser parser = BOParserFactory.GetParser(typeof(T)); 
       parser.PopulateOrdinals(reader); 

       // Use the parser to build our list of BOs. 
       while (reader.Read()) 
       { 
        T BO = default(T); 
        if (propertyNamesToBypassInstantiation == null) 
        { 
         BO = (T)parser.PopulateBO(reader); 
        } 
        else 
        { 
         BO = (T)parser.PopulateBO(reader, propertyNamesToBypassInstantiation); 
        } 
        BOList.Add(BO); 
       } 
       reader.Close(); 
      } 
     } 
     catch (Exception ex) 
     { 
      StringBuilder sb = new StringBuilder(); 
      sb.AppendFormat("Error populating data: {0}", ex.Message); 
      if (ex.InnerException != null) 
      { 
       sb.AppendFormat(" -- Inner Exception: {0}", ex.InnerException.Message); 
      } 
      throw new Exception(sb.ToString(), ex); 
     } 
     finally 
     { 
      command.Connection.Close(); 
      command.Connection.Dispose(); 
     } 

     return BOList; 
    } 

    protected static int GetBOCount(ref SqlCommand command) 
    { 
     int count = 0; 

     try 
     { 
      command.CommandType = CommandType.StoredProcedure; 
      DbParameter idParam = command.CreateParameter(); 
      idParam.DbType = DbType.Int32; 
      idParam.Direction = ParameterDirection.InputOutput; 
      idParam.ParameterName = "@recordCount"; 
      idParam.Value = 0; 
      command.Parameters.Add(idParam); 

      command.Connection.Open(); 
      command.ExecuteNonQuery(); 
      command.Connection.Close(); 
      count = (int)command.Parameters["@recordCount"].Value; 
     } 
     catch (Exception e) 
     { 
      throw new Exception("Error populating data", e); 
     } 
     finally 
     { 
      command.Connection.Close(); 
      command.Connection.Dispose(); 
     } 

     return count; 
    } 

    protected static bool DeleteBO(ref SqlCommand command) 
    { 
     int result = 0; 
     try 
     { 
      command.Connection.Open(); 
      result = command.ExecuteNonQuery(); 
     } 
     catch (Exception e) 
     { 
      throw new Exception("Error deleting data", e); 
     } 
     finally 
     { 
      command.Connection.Close(); 
      command.Connection.Dispose(); 
     } 

     return result > 0; 
    } 


    protected static int GetFKcount(ref SqlCommand command) 
    { 
     int count = 0; 

     try 
     { 
      command.CommandType = CommandType.StoredProcedure; 
      DbParameter idParam = command.CreateParameter(); 
      idParam.DbType = DbType.Int32; 
      idParam.Direction = ParameterDirection.InputOutput; 
      idParam.ParameterName = "@recordCount"; 
      idParam.Value = 0; 
      command.Parameters.Add(idParam); 

      command.Connection.Open(); 
      command.ExecuteNonQuery(); 
      command.Connection.Close(); 
      count = (int)command.Parameters["@recordCount"].Value; 
     } 
     catch (Exception e) 
     { 
      throw new Exception("Error populating data", e); 
     } 
     finally 
     { 
      command.Connection.Close(); 
      command.Connection.Dispose(); 
     } 

     return count; 
    } 

    public static T GetById<T>(Guid Id) 
     where T : BOBase 
    { 
     return GetById<T>(Id, null); 
    } 


    abstract public static T GetById<T>(Guid Id, List<string> propertyNamesToBypassInstantiation) 
     where T : BOBase; 

    public static EquatableList<T> GetByCriteria<T,TCriteria>(TCriteria myCriteria) 
     where T : BOBase 
     where TCriteria : BaseCriteria 
    { 
     return GetByCriteria<T, TCriteria>(myCriteria, null); 
    } 


    public static EquatableList<T> GetByCriteria<T, TCriteria>(TCriteria myCriteria, List<string> propertyNamesToBypassInstantiation) 
     where T : BOBase 
     where TCriteria : BaseCriteria 
    { 
     return GetByCriteria<T, TCriteria>(myCriteria, null, -1, -1, propertyNamesToBypassInstantiation); 
    } 

    public static EquatableList<T> GetByCriteria<T, TCriteria>(TCriteria myCriteria, string sortExpression, int startRowIndex, int maximumRows) 
     where T : BOBase 
     where TCriteria : BaseCriteria 
    { 
     return GetByCriteria<T, TCriteria>(myCriteria, sortExpression, startRowIndex, maximumRows, null); 
    } 

    abstract public static EquatableList<T> GetByCriteria<T, TCriteria>(TCriteria myCriteria, string sortExpression, int startRowIndex, int maximumRows, List<string> propertyNamesToBypassInstantiation) 
     where T : BOBase 
     where TCriteria : BaseCriteria; 

    abstract public static int GetCountForCriteria<TCriteria>(TCriteria myCriteria) 
     where TCriteria : BaseCriteria; 

    abstract public static bool Save<T>(T myobject) 
     where T : BOBase; 


    abstract public static bool Delete<T>(Guid Id) 
     where T : BOBase; 


    abstract public static int GetFKcount<T>(Guid Id) 
     where T : BOBase; 

    abstract internal static void CreateCriteriaParameters<T, TCriteria>(ref SqlCommand myCommand, TCriteria myCriteria) 
     where T : BOBase 
     where TCriteria : BaseCriteria; 
} 

Et cela fait partie du code de la version finale b classe Ottom qui devrait être se retourne:

public partial class PersonDB : DBBase 
{ 

    public override static Person GetById(Guid Id, List<string> propertyNamesToBypassInstantiation) 
    { 
     SqlCommand command = GetDbSprocCommand("sprocPersonSelectSingleItem"); 
     command.Parameters.Add(CreateParameter("@id", Id)); 
     return GetSingleBO<Person>(ref command, propertyNamesToBypassInstantiation); 
    } 

    public override static EquatableList<Person> GetByCriteria(PersonCriteria myCriteria, string sortExpression, int startRowIndex, int maximumRows, List<string> propertyNamesToBypassInstantiation) 
    { 
     SqlCommand command = GetDbSprocCommand("sprocPersonSearchList"); 
     CreateCriteriaParameters(ref command, myCriteria); 
     CreatePagingAndSortingParameters(ref command, sortExpression, startRowIndex, maximumRows); 
     return GetBOEquatableList<Person>(ref command, propertyNamesToBypassInstantiation); 
    } 
} 
+0

Vos classes génériques n'existent pas. – SLaks

+0

Une partie de votre code n'a aucun sens ici. Votre première ligne vous renvoie un: DBBase , mais votre définition DBBase abstraite ne prend aucun paramètre générique. Est-ce que je manque quelque chose? Aussi, je peux vous suggérer de supprimer certains commentaires de code pour améliorer la lisibilité. – CodingGorilla

+0

J'ai supprimé un tas de commentaires pour le rendre plus facile à lire et j'ai corrigé l'erreur où je retournais DBBase au lieu de seulement DBBase. Je l'avais déjà fixé dans mon code, mais en cours d'écriture, la question avait été négligée pour y remédier. –

Répondre

1

Bien que tous les commentaires sur la façon de faire une belle usine générique sont agréables, ce n'était pas ma question. Le problème que je rencontrais était que même si mon usine renvoyait la référence à la classe, je n'étais pas capable d'accéder à aucune des méthodes de la classe. Bien, il s'avère que si vous avez des méthodes statiques sur une classe, elles ne sont pas disponibles quand vous avez une "instance" de cette classe. Puisque toutes mes méthodes dans la classe dérivée sont statiques, je pensais que je ne récupérais pas du tout une instance de ma classe. Il s'est avéré que j'étais ....

Quoi qu'il en soit, puisque ce dont j'avais vraiment besoin était d'obtenir une référence aux méthodes de la classe dérivée, j'ai trouvé une solution qui utilise GetType, GetMethod et MethoInfo.Invoke pour appeler les méthodes à la place.

Voici un exemple:

La méthode où je cherchais à l'origine pour obtenir une référence à la classe dérivée:

public static bobase GetByCriteria<T,TCriteria>(TCriteria myCriteria) 
      where T : bobase 
      where TCriteria : BaseCriteria 
     { 
      T myObject = default(T); 
      Type[] myMethodTypes = new Type[]{typeof(string),typeof(int),typeof(TCriteria)}; 
      System.Reflection.MethodInfo myMethod = myObject.DBclass.GetMethod("GetByCriteria", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static, null, myMethodTypes, null); 
      object[] myMethodParameters = new object[]{"someValueHere", 1, myObject}; 
      return (bobase)myMethod.Invoke(null, myMethodParameters); 
     } 

la classe bobase:

public abstract class bobase 
    { 
     internal virtual Type DBclass 
     { 
      get 
      { 
       return Type.GetType(this.GetType().Name + "DB"); 
      } 
     } 
    } 

Je suis conscient que les trucs GetMethod utilisent la réflexion pour obtenir les données, donc il y a probablement une sorte de coup de performance. S'il y a une meilleure façon d'obtenir une référence à une méthode statique (comme une fabrique de méthodes statiques) qui n'utilise pas la réflexion, j'aimerais en entendre parler.

0

J'utilise dans mes projets d'une usine comme ceci:

public class SomeFactory 
{ 
    private static SomeFactory instance = new SomeFactory(); 

    public static SomeFactory Instance 
    { 
     get 
     { 
      return instance; 
     } 
    } 

    private static Dictionary<Type, Type> classes = new Dictionary<Type, Type>(); 

    static SomeFactory() 
    { 
     // add here classes that would be created by a factory 
     classes.Add(typeof(IClass1), typeof(Class1)); 
     classes.Add(typeof(IClass2), typeof(Class2)); 
    } 

    public T Create<T>() 
    { 
     return (T)System.Activator.CreateInstance(repos[typeof(T)]); 
    } 
} 

utilisation

SomeFactory.Instance.Create<IClass1>()... 
0

pourquoi ne pas utiliser les attributs et créer une usine dynamique

public static classe MyFactory { private static Dictionnaire objects = new Dictionary();

static MyFactory() 
    { 
     // Scan the assembly 
     foreach (Type type in Assembly.GetExecutingAssembly().GetTypes()) 
     { 
      MyAttribute[] frameAttributes = 
       type.GetCustomAttributes(typeof (MyAttribute), false) as MyAttribute[]; 
      foreach (MyAttribute myAttribute in frameAttributes) 
      { 
       objects.Add(myAttribute.SomeKey, type); 
      } 
     } 
    } 
1

Eh bien, DBBase a été définie comme non générique; Cela signifie que vous ne pouvez pas en déclarer une instance générique. C'est la plus grosse erreur de compilation que je vois.

Généralement, le type d'activation est une Rally Bad Idea, car chaque nouveau type que vous voulez que cette usine puisse produire nécessitera un nouveau boîtier. Après une douzaine de nouveaux types, cette déclaration de commutateur sera trop longue pour être maintenue efficacement. Essayez ceci pour votre usine:

public class DALFactory 
{ 
    private Dictionary<Type, Func<DBBase>> factoryMethods; 

    public void Register(Type type, Func<DBBase>> producer) 
    { 
     factoryMethods[type] = producer; //last-in wins 
    } 

    public DBBase GetObject(Type type) 
    { 
     if(factoryMethods.ContainsKey(type)) 
      return factoryMethods[type](); 
     return null; //or throw exception 
    } 

    public Func<DBBase> GetFactoryMethod(Type type) 
    { 
     if(factoryMethods.ContainsKey(type)) 
      return factoryMethods[type]; 
     return null; //or throw exception 
    } 
} 

... 

var factory = new DALFactory(); 
factory.Register(typeof(PersonDB),()=>new PersonDB()); 
//Register other named or anonymous factory methods that produce objects 

Lorsque vous configurez votre usine, vous pouvez vous inscrire autant de méthodes d'usine que vous voulez sans changer l'usine elle-même.