c# - 如何提高自定义 BindingList 上 AddRange 方法的性能?

标签 c# bindinglist addrange

我有一个自定义 BindingList,我想为其创建自定义 AddRange 方法。

public class MyBindingList<I> : BindingList<I>
{
    ...

    public void AddRange(IEnumerable<I> vals)
    {
        foreach (I v in vals)
            Add(v);
    }
}

我的问题是大型集合的性能很糟糕。我现在正在调试的案例是尝试添加大约 30,000 条记录,并且花费了无法接受的时间。

在线查看此问题后,问题似乎在于使用 Add 会在每次添加时调整数组的大小。 This answer我认为总结如下:

If you are using Add, it is resizing the inner array gradually as needed (doubling)

我可以在我的自定义 AddRange 实现中做什么来指定 BindingList 需要根据项目计数调整大小,而不是让它在添加每个项目时不断地重新分配数组?

最佳答案

CSharpie 在他的 answer 中解释道性能不佳是由于 ListChanged -事件在每个 Add 之后触发,并展示了一种实现方式 AddRange为您定制BindingList .

另一种方法是实现 AddRange作为 BindingList<T> 的扩展方法的功能.基于 CSharpies 实现:

/// <summary>
/// Extension methods for <see cref="System.ComponentModel.BindingList{T}"/>.
/// </summary>
public static class BindingListExtensions
{
  /// <summary>
  /// Adds the elements of the specified collection to the end of the <see cref="System.ComponentModel.BindingList{T}"/>,
  /// while only firing the <see cref="System.ComponentModel.BindingList{T}.ListChanged"/>-event once.
  /// </summary>
  /// <typeparam name="T">
  /// The type T of the values of the <see cref="System.ComponentModel.BindingList{T}"/>.
  /// </typeparam>
  /// <param name="bindingList">
  /// The <see cref="System.ComponentModel.BindingList{T}"/> to which the values shall be added.
  /// </param>
  /// <param name="collection">
  /// The collection whose elements should be added to the end of the <see cref="System.ComponentModel.BindingList{T}"/>.
  /// The collection itself cannot be null, but it can contain elements that are null,
  /// if type T is a reference type.
  /// </param>
  /// <exception cref="ArgumentNullException">values is null.</exception>
  public static void AddRange<T>(this System.ComponentModel.BindingList<T> bindingList, IEnumerable<T> collection)
  {
    // The given collection may not be null.
    if (collection == null)
      throw new ArgumentNullException(nameof(collection));

    // Remember the current setting for RaiseListChangedEvents
    // (if it was already deactivated, we shouldn't activate it after adding!).
    var oldRaiseEventsValue = bindingList.RaiseListChangedEvents;

    // Try adding all of the elements to the binding list.
    try
    {
      bindingList.RaiseListChangedEvents = false;

      foreach (var value in collection)
        bindingList.Add(value);
    }

    // Restore the old setting for RaiseListChangedEvents (even if there was an exception),
    // and fire the ListChanged-event once (if RaiseListChangedEvents is activated).
    finally
    {
      bindingList.RaiseListChangedEvents = oldRaiseEventsValue;

      if (bindingList.RaiseListChangedEvents)
        bindingList.ResetBindings();
    }
  }
}

这样,根据您的需要,您甚至可能不需要自己编写 BindingList -子类。

关于c# - 如何提高自定义 BindingList 上 AddRange 方法的性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43331145/

相关文章:

c# - 为什么在 C# Winforms 中控件停靠到其父级时,设计者设置了控件的 "Size"属性?

c# - 处理多个悬停以单击kinect的C#中的事件

C# 服务器 - TCP/IP 套接字效率

c# - 从不同线程 vb.net 更新 BindingList(of T)

c# - ToCharArray 等效于 List<string>

c# - 如何在 wpf 中显示用户对按钮单击的控制?

c# - 从 BindingList 中删除重复项

c#-4.0 - System.ComponentModel.BindingList : Add(object) vs. AddNew()

c# - EF 6.0 DBSet.AddRange() - 如何跳过单个实体错误

c# - 如何在 .NET 3.5 中为 HttpWebRequest 指定 >2GB 的范围