将DataTable转换为通用列表?

8
    public static IList<T> ConvertTo<T>(DataTable table)
    {
        if (table == null)
        {
            return null;
        }

        List<DataRow> rows = new List<DataRow>();

        foreach (DataRow row in table.Rows)
        {
            rows.Add(row);
        }

        return ConvertTo<T>(rows);
    }

    public static T ConvertItem<T>(DataTable table)
    {
        T obj = default(T);
        if (table != null && table.Rows.Count > 0)
        {
            obj = CreateItem<T>(table.Rows[0]);
        }
        return obj;
    }


    public static T CreateItem<T>(DataRow row)
    {
        T obj = default(T);
        if (row != null)
        {
            obj = Activator.CreateInstance<T>();
            Type entityType = typeof(T);
            PropertyInfo[] properties = entityType.GetProperties();

            for (int i = 0; i < properties.Length; i++)
            {
                object[] customAttributes = properties[i].GetCustomAttributes(typeof(ColumnAttributes), false);
                ColumnAttributes dataField = null;
                if (null != customAttributes && customAttributes.Length > 0 && null != (dataField = customAttributes[0] as ColumnAttributes))
                {
                    if (row.Table.Columns.Contains(dataField.FieldName) && !row[dataField.FieldName].GetType().FullName.Equals("System.DBNull"))
                    {
                        properties[i].SetValue(obj, row[dataField.FieldName], null);
                    }
                }
            }
        }
        return obj;
    }

我们目前能想到的唯一可能是:我们正在执行某些操作,需要自行进行垃圾回收?

你有何想法?

为什么我们认为可能存在泄漏?:

我们遇到了内存不足错误。如果页面不需要业务逻辑使用这种转换类型,则 II6 进程不会增长;但当我们访问需要使用它的页面时,进程会增长。

我们目前正在使用 ANTS Profiler 以获取更多详细信息。


你有什么泄漏的证据? - Mitch Wheat
问题具体在哪里? - Gerrie Schenck
我的第一反应是你不应该自己调用GC.Collect。根据你提供的信息,我没有看到任何真正的问题。你尝试过使用分析器进行检查吗? - Gerrie Schenck
有一种通用方法可以将您的 DT 转换为通用列表。请参见以下链接:http://www.dotnetobject.com/Thread-Dataset-to-Generic-List-conversion-in-c?pid=8297#pid8297 - user1846636
1个回答

10

这不会是一个实际的“泄漏”,但可能会不必要地增加压力...

你正在处理多少行? 请注意,反射是很麻烦的,而且像GetCustomAttributes这样的每个调用都可以返回一个新数组(因此您只需要执行一次,而不是对于每个属性-每个行都执行一次)。

就我个人而言,我会预先构建我要做的工作...类似下面的东西。

请注意,如果我经常这样做,我要么切换到HyperDescriptor,要么如果.NET 3.5是一个选项,可能是一个编译表达式。由于DataTable没有强类型,所以在下面之后,HyperDescriptor将是一个逻辑下一步(为了性能)...

sealed class Tuple<T1, T2>
{
    public Tuple() {}
    public Tuple(T1 value1, T2 value2) {Value1 = value1; Value2 = value2;}
    public T1 Value1 {get;set;}
    public T2 Value2 {get;set;}
}
public static List<T> Convert<T>(DataTable table)
    where T : class, new()
{
    List<Tuple<DataColumn, PropertyInfo>> map =
        new List<Tuple<DataColumn,PropertyInfo>>();

    foreach(PropertyInfo pi in typeof(T).GetProperties())
    {
        ColumnAttribute col = (ColumnAttribute)
            Attribute.GetCustomAttribute(pi, typeof(ColumnAttribute));
        if(col == null) continue;
        if(table.Columns.Contains(col.FieldName))
        {
            map.Add(new Tuple<DataColumn,PropertyInfo>(
                table.Columns[col.FieldName], pi));
        }
    }

    List<T> list = new List<T>(table.Rows.Count);
    foreach(DataRow row in table.Rows)
    {
        if(row == null)
        {
            list.Add(null);
            continue;
        }
        T item = new T();
        foreach(Tuple<DataColumn,PropertyInfo> pair in map) {
            object value = row[pair.Value1];
            if(value is DBNull) value = null;
            pair.Value2.SetValue(item, value, null);
        }
        list.Add(item);
    }
    return list;        
}

我同意Marc的观点。你的代码既慢又相当复杂!此外,你应该检查属性的类型,以便不会尝试将int值设置为字符串值等等。 - Rune Grimstad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接