2009-04-23 15 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はそれが知っている型または名前空間ではなく、非総称宣言のどこにTを使うことができないと文句を言う。

これはできませんか?

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

私はコンストラクタにするDataRowを渡すことはできませんが、あなたはBusinessBaseのプロパティに割り当てることによってこれを解決することができます:あなたは、おそらく次のように、T上のnewジェネリック制約を追加する必要があります

答えて

21

追加した2つの大きな問題があると思う:

  • あなたは
  • パラメータを取るあなたの方法は、現在一般的なではないコンストラクタ制約を指定することはできません - それはPopulateCollection<T>の代わりPopulateCollectionでなければなりません。

    public abstract void PopulateFrom(DataRow dr); 
    

    はまた、パラメータなしのコンストラクタの制約を追加:

あなたはすでに私はあなたがBusinessBaseに抽象的(または仮想)メソッドを追加提案T : BusinessBaseは、その第一の問題ラウンドを取得するという制約を持っています〜T

あなたの方法は、その後になることができ

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で拡張メソッドを使用して、これは少し簡単にすることができます。また

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

、あなたは可能性がありそれを拡張メソッド(.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(); 
} 
人の

あなたの発信者は、次に記述します。これは想定してい

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

あなたは、コンストラクタDataRowを服用を持つに戻ります。これには、不変クラス(およびパラメータのないコンストラクタを持たないクラス)を書くことができるという利点がありますが、 "ファクトリ"関数も持たずに一般的には使えないということを意味します。

+0

+1この問題と最後のバージョンについてはっきりしています。この場合、中間バージョンはforeachよりはるかに簡単だとは思わない。 – eglasius

+0

私は編集する権限がありませんので、誰でも変更できます。 dt.Rows.AsEnumerable()を返します。Select(selector).ToList(); 〜 return dt.AsEnumerable()。Select(セレクタ).ToList(); AsEnumerableは.RowsコレクションにないDataTableの拡張メソッドです。 – AngryHacker

+0

@AngryHacker:ありがとう、終わった。 –

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

パブリッククラスBusinessBase {public DataRow DataRow {get;セット; }} – Simon

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を受け入れるコンストラクタを使用して、その派生クラスのオブジェクトをインスタンス化するための静的メソッドを有します。