Winfrom ComboBox中的性能探索


在为Control维护元素列表的过程中,会不可避免的造成性能损耗,我们接下来要探究的就是哪种方式才是我们的最优解。

方案比较

以ComboBox为例,常见的方式一共有两种:Add、AddRange。

Add

List vs = new List();
            for (int i = 0; i < 100; i++)
            {
                vs.Add(i);
            }
            Stopwatch sw = new Stopwatch();
            sw.Start();
            
            comboBox1.Items.Add(vs);
            sw.Stop();
            TimeSpan ts = sw.Elapsed;
            Console.WriteLine("DateTime costed for Shuffle function is: {0}ms", ts.TotalMilliseconds);

DateTime costed for Shuffle function is: 44.9402ms

AddRange

object[] obj = new object[100];
            for (int i = 0; i < 100; i++)
            {
                obj[i] = i;
            }
            Stopwatch sw = new Stopwatch();
            sw.Start();
            comboBox1.Items.AddRange(obj);
            sw.Stop();
            TimeSpan ts = sw.Elapsed;
            Console.WriteLine("DateTime costed for Shuffle function is: {0}ms", ts.TotalMilliseconds);

DateTime costed for Shuffle function is: 25.6242ms

试验比较粗糙,但是也反映了一些基本结论:AddRange要比Add的性能高出一些。

探源

public void AddRange(object[] items) {
                owner.CheckNoDataSource();
                owner.BeginUpdate();
                try
                {
                    AddRangeInternal(items);
                }
                finally
                {
                    owner.EndUpdate();
                }
            }


internal void AddRangeInternal(IList items) {

                if (items == null)
                {
                    throw new ArgumentNullException("items");
                }
                foreach (object item in items) {
                    // adding items one-by-one for performance (especially for sorted combobox)
                    // we can not rely on ArrayList.Sort since its worst case complexity is n*n
                    // AddInternal is based on BinarySearch and ensures n*log(n) complexity
                    AddInternal(item);
                }
                if (owner.AutoCompleteSource == AutoCompleteSource.ListItems)
                {
                    owner.SetAutoComplete(false, false);
                }
            }

我们可以看到,对于上面的结论,微软给了我们一个解释:因为Add方法的原理是基于ArrayList,它的性能最低情况为n*n。而AddRange的内部原理则是基于二分法,最低性能为n*log(n),因此当需维护项较多时,应优先考虑使用AddRange进行维护。