2009-04-23 83 views
3

我對仿製藥有點生疏,努力做到以下幾點,但是編譯器會抱怨:C#泛型問題

protected List<T> PopulateCollection(DataTable dt) where T: BusinessBase 
{ 
    List<T> lst = new List<T>(); 
    foreach (DataRow dr in dt.Rows) 
    { 
     T t = new T(dr); 
     lst.Add(t); 
    } 
    return lst; 
} 

因此,大家可以看到,我試圖轉儲表的內容轉換成對象(通過將DataRow傳遞給構造函數),然後將該對象添加到集合中。它抱怨T不是它知道的類型或名稱空間,而且我也不能在非泛型聲明中使用它。

這不可能嗎?

回答

21

有兩個大問題:

  • 不能指定一個構造函數約束,這需要參數
  • 你的方法不是當前通用的 - 它應該是PopulateCollection<T>而不是PopulateCollection

你已經有了一個約束T : BusinessBase,所以要避開的第一個問題,我建議你在BusinessBase添加一個抽象的(或者虛擬的)方法:

public abstract void PopulateFrom(DataRow dr); 

同時添加參數的構造函數約束到T

那麼你的方法能成爲:

protected List<T> PopulateCollection<T>(DataTable dt) 
    where T: BusinessBase, new() 
{ 
    return dt.AsEnumerable().Select(dr => 
    { 
     T t = new T(); 
     t.PopulateFrom(dr); 
    }.ToList(); 
} 

或者,您可以:

protected List<T> PopulateCollection(DataTable dt) 
    where T: BusinessBase, new() 
{ 
    List<T> lst = new List<T>(); 
    foreach (DataRow dr in dt.Rows) 
    { 
     T t = new T(); 
     t.PopulateFrom(dr); 
     lst.Add(t); 
    } 
    return lst; 
} 

如果您使用.NET 3.5,您可以在此稍微簡單使用DataTableExtensions擴展方法使使其成爲擴展方法本身(再次假設.NET 3.5)並傳入函數以返回實例:

static List<T> ToList<T>(this DataTable dt, Func<DataRow dr, T> selector) 
    where T: BusinessBase 
{ 
    return dt.AsEnumerable().Select(selector).ToList(); 
} 
01然後級

您的呼叫會寫:

table.ToList(row => new Whatever(row)); 

這是假設你回去有一個構造採取DataRow。這樣做的好處是可以編寫不可變類(以及沒有無參數構造函數的類),但這意味着如果沒有「工廠」功能,就無法工作。

+0

+1清除問題,併爲最後的版本。在這種情況下,我認爲中間版本並不比foreach簡單。 – eglasius 2009-04-23 09:04:05

+0

我沒有編輯的權力,所以任何人都可以,改變 返回dt.Rows.AsEnumerable()。Select(selector).ToList(); 至 return dt.AsEnumerable()。Select(selector).ToList(); 因爲AsEnumerable是不在.Rows集合上的DataTable的擴展方法。 – AngryHacker 2009-05-15 04:44:26

2

你可能需要添加T上的new泛型約束,如下:

protected List<T> PopulateCollection<T>(DataTable dt) where T : BusinessBase, new() 
... 

我不能通過一個DataRow到構造函數,但是你可以通過將其分配給的BusinessBase屬性解決

0
where T: BusinessBase 

應該有有)新的限制(我想補充

3

唯一的constraint你可以指定哪個允許創建新的實例new() - 基本上是一個無參數的構造函數。爲了避免這種做或者:

interface ISupportInitializeFromDataRow 
{ 
    void InitializeFromDataRow(DataRow dataRow); 
} 

protected List<T> PopulateCollection<T>(DataTable dt) 
    where T : BusinessBase, ISupportInitializeFromDataRow, new() 
{ 
    List<T> lst = new List<T>(); 
    foreach (DataRow dr in dt.Rows) 
    { 
     T t = new T(); 
     t.InitializeFromDataRow(dr); 

     lst.Add(t); 
    } 
    return lst; 
} 

或者

protected List<T> PopulateCollection<T>(DataTable dt, Func<DataRow, T> builder) 
    where T : BusinessBase 
{ 
    List<T> lst = new List<T>(); 
    foreach (DataRow dr in dt.Rows) 
    { 
     T t = builder(dr);   
     lst.Add(t); 
    } 
    return lst; 
} 
2

一種可能的方式是:

protected List<T> PopulateCollection<T>(DataTable dt) where T: BusinessBase, new() 
    { 
     List<T> lst = new List<T>(); 
     foreach (DataRow dr in dt.Rows) 
     { 
      T t = new T(); 
      t.DataRow = dr; 
      lst.Add(t); 
     } 
     return lst; 
    } 
0

這是可能的。我在我的框架中完全一樣。我和你有完全一樣的問題,這就是我解決問題的方法。從框架中發佈相關片段。如果我記得correclty,最大的問題是需要調用無參數構造函數。

public class Book<APClass> : Book where APClass : APBase 
     private DataTable Table ; // data 
     public override IEnumerator GetEnumerator() 
     {       
      for (position = 0; position < Table.Rows.Count; position++)   
       yield return APBase.NewFromRow<APClass>(Table.Rows[position], this.IsOffline); 
     } 
    ... 


    public class APBase ... 
    { 
    ... 
    internal static T NewFromRow<T>(DataRow dr, bool offline) where T : APBase 
     { 

      Type t = typeof(T); 
      ConstructorInfo ci; 

      if (!ciDict.ContainsKey(t)) 
      { 
       ci = t.GetConstructor(new Type[1] { typeof(DataRow) }); 
       ciDict.Add(t, ci); 
      } 
      else ci = ciDict[t]; 

      T result = (T)ci.Invoke(new Object[] { dr }); 

      if (offline) 
       result.drCache = dr;  

      return result; 
     } 

在這種情況下,基類有靜態方法來實例化使用接受tablerow的構造函數的派生類的對象。