C#泛型问题

C#泛型问题,c#,generics,collections,C#,Generics,Collections,我对泛型有点生疏,尝试执行以下操作,但编译器抱怨: 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); } r

我对泛型有点生疏,尝试执行以下操作,但编译器抱怨:

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;
}
受保护列表PopulateCollection(DataTable dt),其中T:BusinessBase
{
List lst=新列表();
foreach(数据行dr在dt.行中)
{
T=新的T(dr);
第1条增补(t);
}
返回lst;
}
如您所见,我试图将表的内容转储到对象中(通过向构造函数传递数据行),然后将对象添加到集合中。它抱怨T不是它知道的类型或名称空间,我不能在非泛型声明中使用where


这是不可能的吗?

您可能需要在T上添加
新的
通用约束,如下所示:

protected List<T> PopulateCollection<T>(DataTable dt) where T : BusinessBase, new()
...
protectedlist PopulateCollection(DataTable dt),其中T:BusinessBase,new()
...
我无法将数据行传递给构造函数,但您可以通过将其分配给
BusinessBase

where T: BusinessBase

应该有new()的限制,我想添加了两个大问题:

  • 不能指定接受参数的构造函数约束
  • 您的方法当前不是泛型的-它应该是
    PopulateCollection
    而不是
    PopulateCollection
您已经有了一个约束
T:BusinessBase
,因此为了解决第一个问题,我建议您在
BusinessBase
中添加一个抽象(或虚拟)方法:

public abstract void PopulateFrom(DataRow dr);
还将无参数构造函数约束添加到
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),并传入一个函数以返回实例:

static List<T> ToList<T>(this DataTable dt, Func<DataRow dr, T> selector)
    where T: BusinessBase
{
    return dt.AsEnumerable().Select(selector).ToList();
}
这假设您返回到一个构造函数获取一个
DataRow
。这样做的好处是允许您编写不可变类(以及没有无参数构造函数的类),但这确实意味着您不能在没有“factory”函数的情况下进行一般性工作。

唯一可以指定允许创建新实例的类是
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;
}
接口ISupportInitializeFromDataRow
{
void InitializeFromDataRow(DataRow DataRow);
}
受保护列表PopulateCollection(数据表dt)
其中T:BusinessBase,ISupportInitializeFromDataRow,new()
{
List lst=新列表();
foreach(数据行dr在dt.行中)
{
T=新的T();
t、 初始化FromDataRow(dr);
第1条增补(t);
}
返回lst;
}

受保护的列表PopulateCollection(数据表dt,Func builder)
where T:BusinessBase
{
List lst=新列表();
foreach(数据行dr在dt.行中)
{
T=建造商(dr);
第1条增补(t);
}
返回lst;
}
一种可能的方法是:

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;
    }
protectedlist PopulateCollection(DataTable dt),其中T:BusinessBase,new()
{
List lst=新列表();
foreach(数据行dr在dt.行中)
{
T=新的T();
t、 DataRow=dr;
第1条增补(t);
}
返回lst;
}

这是可能的。我的框架中有完全相同的东西。我和你的问题完全一样,我就是这样解决的。发布框架中的相关片段。如果我记得正确的话,最大的问题是需要调用无参数构造函数

 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;
        }
public class Book:Book其中APClass:APBase
私有数据表;//数据
公共重写IEnumerator GetEnumerator()
{                        
对于(位置=0;位置

在此场景中,基类有一个静态方法,使用接受tablerow的构造函数实例化其派生类的对象。

public class BusinessBase{public DataRow DataRow{get;set;}+我清楚这些问题,对于最后一个版本,我不认为中间版本比foreach更简单。在这种情况下,我没有编辑的权力,所以任何人都可以更改return dt.Rows.AsEnumerable().Select(selector.ToList();return dt.AsEnumerable().Select(selector.ToList());因为AsEnumerable是DataTable上的扩展方法,而不是.Rows集合上的扩展方法。
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;
}
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;
    }
 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;
        }