繁体   English   中英

C#泛型问题

[英]C# Generics question

我对泛型有点生疏,尝试做以下事情,但编译器抱怨:

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不是它所知道的类型或命名空间,并且我不能在非泛型声明中使用它。

这不可能吗?

有两个大问题:

  • 您不能指定带参数的构造函数约束
  • 您的方法目前不是通用的 - 它应该是PopulateCollection<T>而不是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,则可以使用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 这样做的好处是允许你编写不可变类(以及没有无参数构造函数的类),但这意味着你不能在没有“工厂”功能的情况下一般地工作。

您可以指定允许创建新实例的唯一约束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;
}

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

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

我无法将DataRow传递给构造函数,但您可以通过将其分配给BusinessBase的属性来解决这个问题

一种可能的方法是:

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;
    }
where T: BusinessBase

应该有新的限制()我想补充

有可能的。 我的框架中有完全相同的东西。 我和你有完全相同的问题,这就是我解决它的方法。 从框架中发布相关的片段。 如果我记得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的构造函数来实例化其派生类的对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM