2010-09-17 55 views
0

我想創建一個類,使用工廠來找到正確的類,然後調用該類的方法。 我做錯了什麼,雖然因爲在Visual Studio中的intellisense不斷警告我的錯誤,當我嘗試訪問類應該在工廠返回他們不可用的方法。類的通用工廠?

誰能告訴我我做錯了什麼?

這裏就是我想要去的類的引用代碼:

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

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

下面是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"); 
     } 
} 

下面是部分代碼由工廠類返回的類的基類:

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; 
} 

而這是最終的代碼的一部分b應該得到返回ottom類:

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

您的泛型類不存在。 – SLaks 2010-09-17 20:42:44

+0

這裏的一些代碼沒有任何意義。你的第一行你將返回一個:DBBase ,但是你的抽象DBBase定義不會使用任何通用參數。我錯過了什麼嗎?另外,我可以建議你去掉一些代碼註釋以提高可讀性。 – CodingGorilla 2010-09-17 20:44:32

+0

我刪除了一堆評論,以便更容易閱讀,並修復了我返回DBBase 而不僅僅是DBBase的錯誤。我已經在我的代碼中解決了這個問題,但是在寫出這個問題的過程中,我已經選擇了將它修復的問題。 – 2010-09-18 01:38:28

回答

1

儘管關於如何製作一個很好的通用工廠的所有評論都很好,但這不是我的問題。我遇到的問題是,即使我的工廠正在返回該類的引用,但我無法訪問該類中的任何方法。

嗯,事實證明,如果你有一個類的靜態方法,它們不可用時,當你有一個該類的「實例」。由於派生類中的所有方法都是靜態的,所以我認爲我實際上並沒有回到我的類的實例。原來我是......

無論如何,因爲我真正需要的是獲得對派生類中方法的引用的方法,所以我找到了一個使用GetType,GetMethod和MethoInfo.Invoke來調用的方法來調用相反的方法。

下面是一個例子:

,我本來試圖去派生類的引用方法:

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); 
     } 

的bobase類:

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

我知道GetMethod的東西使用反射來獲取數據,所以可能會有某種性能問題。如果有一種更好的方法來獲得對靜態方法(如靜態方法工廠)的引用,那麼不會使用反射,我很樂意聽到它。

0

我在我的項目使用一個工廠這樣的:

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)]); 
    } 
} 

使用

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

爲什麼不使用屬性,並創建一個動態的工廠

public static class MyFactory { private static Dictionary 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

那麼,DBBase被定義爲非泛型的;這意味着你不能聲明它的一個通用實例。這是我看到的最大的編譯時錯誤。

通常情況下,開啓類型是一個拉力不佳的想法,因爲你想這個工廠能夠產生的每一種新類型都需要一個新的案例。在幾十種新類型之後,這個switch語句將會太長而無法有效維護。試一試:

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 

設置您的工廠時,您可以根據需要註冊許多工廠方法,而無需更改工廠本身。