0

这不是一个真正的问题,但更多的是一个问题,我希望您能提供一些意见。

Winforms C# .net3.5[sp1] Visual Studio 2008 使用 Linq2Sql (更具体地说是PLINQO ...这太棒了顺便说一句!)。我有一个返回 +/- 19000 行数据(每行大约 80 字节数据)的结果集,并选择将数据检索方法推送到后台并相应地更新 UI。这工作正常。

但是,当我的 Ling 数据检索方法使用不同的返回类型时,我注意到了一些性能差异。我知道每个人都建议返回一个List<T>or IEnumarable<T>,并将 DataGridView 的数据源设置为那个,但不幸的是它不支持对对象进行本地排序。经过一番挖掘,我在这里找到了SortableBindingList<T>MSDN 上。我应用了它,并且 Grid 花了不到一秒钟的时间来填充自己 - 但是当我单击一列对其进行排序时,实现排序需要一秒钟左右的时间。

然后我决定走 DataTable 路线,但发现 ToDataTable 方法已被删除,但经过更多挖掘,在这篇MSDN 文章中找到了实现它的方法。应用它后,我发现检索需要大约 2 秒来填充网格,但此后排序(在 19000 行上!)是瞬间的!我自然而然地坚持了这种方法。

另请记住,我已禁用任何网格内编辑/添加/删除。网格纯粹用于显示数据。任何其他 CRUD 操作都由对话框表单根据当前选定的行(隐藏的主键列)提供。

这是我用于两种方法的代码:

1) 排序绑定列表

    //declare private member
    private SortableBindingList<PdtAllocation> listAlloc = null;

    private void RefreshData() {
        bcsDataContext ctx = new bcsDataContext();
        try {
            listAlloc = new SortableBindingList<PdtAllocation>(ctx.PdtAllocation.ToList());
        }
        catch (Exception) {
            throw;
        }
        finally {
            ctx.Dispose();
        }

        dataGridView1.DataSource = listAlloc;
    }

2) 复制到数据表

    //declare private member
    private DataTable dt = null;

    private void RefreshData() {
        dt = new DataTable();
        bcsDataContext ctx = new bcsDataContext();
        try {
            ctx.PdtAllocation.CopyToDataTable(dt, LoadOption.PreserveChanges);
        }
        catch (Exception) {
            throw;
        }
        finally {
            ctx.Dispose();
        }

        dataGridView1.DataSource = dt;
    }

现在我知道这可能看起来像是一个“有问必答”的案例,但我非常感谢您的意见,以及任何已知的CopyToDataTable()路线问题。

谢谢你....并为 looong 查询道歉!

4

1 回答 1

1

这是我对你的问题的看法(走这SortableBindingList条路)。

您是否使用了基于反射的通用排序算法?我一开始就这样做了,性能真的很差。最后我想出了以下解决方案:提供默认排序,SortableBindingList<T>但也保留在派生类中实现专门排序的可能性。

这是一些代码。

SortableBindingList<T>.ApplySortCore()

protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
    // Check if the sorted property implements IComparable
    ...

    List<T> itemsList = (List<T>)this.Items;

    Comparison<T> comparer = GetComparer(prop);

    itemsList.Sort(comparer);

    if (direction == ListSortDirection.Descending)
    {
        itemsList.Reverse();
    }

    ...
    // Set sort state (is sorted, sort property, sort dir)
}

泛型SortableBindingList<T>提供了一个基本的、基于反射的排序器:

protected virtual Comparison<T> GetComparer(PropertyDescriptor prop)
{
    return new Comparison<T>(delegate(T x, T y)
    {
        if (prop.GetValue(x) != null)
            return ((IComparable)prop.GetValue(x)).CompareTo(prop.GetValue(y));
        else if (prop.GetValue(y) != null)
            return -1 * ((IComparable)prop.GetValue(y)).CompareTo(prop.GetValue(x));
        else
            return 0;
    });
}

如您所见,GetComparer()它是虚拟的,因此可以在派生的类中覆盖它,SortableBindingList<T>以提供更快的比较器,并根据实际排序的属性类型进行调整。例如,通用比较器String在 4 秒内(按属性)排序了 10000 条记录,而专用比较器在 70 毫秒内完成了相同的工作。

class CustomerList : SortableBindingList<Customer>
{
    protected override Comparison<Customer> GetComparer(PropertyDescriptor prop)
    {
        Comparison<Customer> comparer = null;
        switch (prop.Name)
        {
            case "FirstName":
                comparer = new Comparison<Customer>(delegate(Customer x, Customer y)
                {
                    string xx = (null == x) ? null : x.FirstName;
                    string yy = (null == y) ? null : y.FirstName;
                    return String.Compare(xx, yy);
                });
                break;
            ...
        }
        return comparer;
    }
}

最后一点:发布的大部分代码都是从其他来源复制/启发的,比如 SO 或 Microsoft,所以这不是我的功劳。我唯一的贡献是虚拟化比较器,但我确信稍微搜索一下会更好,基于相同想法的早期解决方案。

于 2009-11-19T16:28:25.457 回答