为什么ObservableCollection<;T>;有两个集合构造函数
本文关键字:两个 集合 构造函数 lt ObservableCollection gt 为什么 | 更新日期: 2023-09-27 18:19:52
ObservableCollection(T)类有两个构造函数,其中可以传递项的集合。一个构造函数接受IEnumerable(T)
,而另一个构造函数则接受List(T)
。
既然List(T)
实现了IEnumerable(T)
,为什么存在第二个构造函数?
采用List
的构造函数是在.NET 3.0中引入的,而采用IEnumerable
的构造函数直到.NET 3.5才引入,因此删除List
构造函数将是一个巨大的变化。
我猜他们写它是为了接受List
,然后发货,后来意识到它可以更通用。
源代码也有一个有趣的注释(不确定它是否相关):
public ObservableCollection(List<T> list)
: base((list != null) ? new List<T>(list.Count) : list)
{
// Workaround for VSWhidbey bug 562681 (tracked by Windows bug 1369339).
// We should be able to simply call the base(list) ctor. But Collection<T>
// doesn't copy the list (contrary to the documentation) - it uses the
// list directly as its storage. So we do the copying here.
//
CopyFrom(list);
}
public ObservableCollection(IEnumerable<T> collection)
{
if (collection == null)
throw new ArgumentNullException("collection");
CopyFrom(collection);
}
看看这里的来源:
http://referencesource.microsoft.com/#System/compmod/system/collections/objectmodel/observablecollection.cs,f63ea2601f5edbbb
如果不挖得太深,你会注意到:
public ObservableCollection(List<T> list)
: base((list != null) ? new List<T>(list.Count) : list)
{
// Workaround for VSWhidbey bug 562681 (tracked by Windows bug 1369339).
// We should be able to simply call the base(list) ctor. But Collection<T>
// doesn't copy the list (contrary to the documentation) - it uses the
// list directly as its storage. So we do the copying here.
//
CopyFrom(list);
}
这个:
public ObservableCollection(IEnumerable<T> collection)
{
if (collection == null)
throw new ArgumentNullException("collection");
CopyFrom(collection);
}
请注意,在传递List<T>
的情况下,它会用一个新的List<T>
调用基构造函数,它的容量已经设置为与您传递的列表的Count
相匹配。显然,您不能用IEnumerable<T>
来实现这一点,因为IEnumerable<T>
没有Count
属性。所以它看起来像是一个优化。如果您已经知道集合将有多大,那么当您将源复制到内部List<T>
时,可以避免由于调整其大小而造成的损失。
编辑:还有@DStanley关于打破变化的观点。无论如何,这可能更重要再次编辑:或者不编辑,因为文档中似乎有一些混乱。但我创建了一个以.NET 3.0为目标的项目,看起来两个构造函数都在那里。如果我在Visual Studio中使用"转到定义",我可以看到:
#region Assembly WindowsBase.dll, v3.0.0.0
// C:'Program Files (x86)'Reference Assemblies'Microsoft'Framework'v3.0'WindowsBase.dll
#endregion
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
namespace System.Collections.ObjectModel
{
[Serializable]
public class ObservableCollection<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged
{
public ObservableCollection();
public ObservableCollection(IEnumerable<T> collection);
public ObservableCollection(List<T> list);
//....
而这段代码,在.NET 3.0中编译得很好:
var list = new List<int>() {1,2,3};
IEnumerable<int> enumerable = (IEnumerable<int>)list;
var obsWithList = new ObservableCollection<int>(list);
var obsWithEnumerable = new ObservableCollection<int>(enumerable);
经过一点反思:
var internalListProp = typeof(ObservableCollection<int>).GetProperty("Items", BindingFlags.NonPublic | BindingFlags.Instance);
var l0 = (internalListProp.GetValue(obsWithList, null) as List<int>).Capacity; // 3
var l1 = (internalListProp.GetValue(obsWithEnumerable, null) as List<int>).Capacity; // 4
您可以看到,当传入List<T>
时,内部列表的容量被设置为与Count
相匹配,但当传递IEnumerable<T>
时则不匹配。