2011-10-14 30 views
3

我有一個功能,像這樣:我可以使用通用約束來啓用參數化構造函數嗎?

public List<T> SelectAll<T>() where T : DatabaseObject, new() 
{ 
    List<T> retVal = new List<T>(); 
    String command = "Select * from " + GetType().Name; 
    MySqlCommand cmd = DatabaseRunner.GetCommand(command); 
    MySqlDataReader reader = cmd.ExecuteReader(); 
    while (reader.Read()) 
    { 
     T newObj = new T(reader); 
    } 
    return retVal; 
} 

你可以看到,當我嘗試創建一個新的T對象,我傳遞一個MySqlDataReader對象的構造函數。我如何修改方法簽名來允許這個?

+0

你可以欺騙,令T貫徹含有創建一個新的T和一個帶有參數的單一工廠方法的接口。那種醜陋,但它擊敗IMO的反映。 – harold

回答

9

你不能。 C#僅支持new()約束(您已經使用它)來將類型參數限制爲具有無參數構造函數的類型。具有參數的構造函數在此上下文中不受支持。

+2

我會建議,而不是你想要的是一個接口,它有一個參數,它需要一個'SqlDataReader'並根據需要讀取(並初始化)該對象。 – CodingGorilla

7

你不能用約束來做到這一點。但是,您可以調用該方法,並傳遞一個函數來創建一個TMySqlDataReader

public List<T> SelectAll<T>(Func<MySqlDataReader, T> projection) 
    where T : DatabaseObject 
{ 
    List<T> retVal = new List<T>(); 
    String command = "Select * from " + GetType().Name; 
    MySqlCommand cmd = DatabaseRunner.GetCommand(command); 
    MySqlDataReader reader = cmd.ExecuteReader(); 
    while (reader.Read()) 
    { 
     retValue.Add(projection(reader)); 
    } 
    return retVal; 
} 

(您可能需要使用DbDataReader,而不是MySqlDataReader,以避免太過具體。)

另一個另一種方法是給DatabaseObject類似的Initialize(DbDataReader reader)方法,那麼你可以使用:

public List<T> SelectAll<T>() where T : DatabaseObject, new() 
{ 
    List<T> retVal = new List<T>(); 
    String command = "Select * from " + GetType().Name; 
    MySqlCommand cmd = DatabaseRunner.GetCommand(command); 
    MySqlDataReader reader = cmd.ExecuteReader(); 
    while (reader.Read()) 
    { 
     T value = new T(); 
     value.Initialize(reader); 
     retValue.Add(value); 
    } 
    return retVal; 
} 

作爲一個方面的問題,你不處置的任何東西 - 喲你應該使用using語句來自動處理閱讀器和命令。

+0

我剛剛寫完第二個IDENTICAL代碼!好的回答:) –

8

簡答題是你不能。解決此問題的方法是刪除new()約束,並使用Activator.CreateInstance()

T value = (T) Activator.CreateInstance(typeof(T), reader) 
+0

記得把結果轉換成'T'。 –

+0

良好的捕獲,補充。 – jrummell

相關問題