在C#中,获取一个类型化且只读的空列表的标准方式是什么,还是有其他方法吗?
注:对于那些问“为什么”的人:我有一个虚拟方法返回一个 IList
(或更确切地说,是一个IEnumerable
),默认实现为空。无论列表返回什么内容都应该是只读的,因为写入它将是一个错误,如果有人尝试写入,我希望立即停止并捕获错误,而不是等待错误以某种微妙的方式出现。
在C#中,获取一个类型化且只读的空列表的标准方式是什么,还是有其他方法吗?
注:对于那些问“为什么”的人:我有一个虚拟方法返回一个 IList
(或更确切地说,是一个IEnumerable
),默认实现为空。无论列表返回什么内容都应该是只读的,因为写入它将是一个错误,如果有人尝试写入,我希望立即停止并捕获错误,而不是等待错误以某种微妙的方式出现。
个人认为,这比其他任何答案都更好:
static readonly IList<T> EmptyList = new T[0];
IList<T>
接口。new List<T>().AsReadOnly()
简单得多。IList<T>
(如果需要的话)。顺便提一下,如果我没记错的话,Enumerable.Empty<T>()
实际上就是使用了这种方式。所以从理论上讲,你甚至可以这样做:(IList<T>)Enumerable.Empty<T>()
(尽管我认为没有太好的理由这样做)。
你可以创建一个列表:
List<MyType> list = new List<MyType>();
如果你想要一个空的 IEnumerable<T>
,使用 Enumerable.Empty<T>()
:
IEnumerable<MyType> collection = Enumerable.Empty<MyType>();
如果你真正想要一个只读列表,可以这样做:
IList<MyType> readonlyList = (new List<MyType>()).AsReadOnly();
这将返回一个ReadOnlyCollection<T>
,它实现了IList<T>
。
null
。理想情况下,你会希望出于内存节省的原因而引用相同的只读空集合,就像使用 string.Empty
一样。 - jpaugh从 .net 4.6 开始,您还可以使用以下内容:
IList<T> emptyList = Array.Empty<T>();
这只会为您指定的每种不同类型 T 创建一个新实例。
IList<T> list = new List<T>().AsReadOnly();
或者,如果您想要一个 IEnumerable<>
:
IEnumerable<T> sequence = Enumerable.Empty<T>();
ReadOnlyCollection<Foo> foos = new List<Foo>().AsReadOnly();
System.Collections.ObjectModel.ReadOnlyCollection
的实例。List<int> items = new List<int>();
ReadOnlyCollection<int> readOnlyItems = new ReadOnlyCollection<int>(items);
进一步扩展丹·陶(Dan Tao)的答案,可以使用以下实现方式,以与Enumerable.Empty<T>()
相同的方式使用,只需指定List.Empty<T>()
即可。
public static class List
{
public static IList<T> Empty<T>()
{
// Note that the static type is only instantiated when
// it is needed, and only then is the T[0] object created, once.
return EmptyArray<T>.Instance;
}
private sealed class EmptyArray<T>
{
public static readonly T[] Instance = new T[0];
}
}
编辑:我根据与Dan Tao关于Instance
字段的延迟初始化和急切初始化的讨论,更改了上面的代码以反映结果。
List.Empty<T>()
可能会得到不同的对象),并且几乎没有什么好处(你认为单个零长度数组的初始化成本与JIT编译新类的成本相比如何?)。使用急切初始化的static readonly
公共字段,或者-如果你的良心不允许-一个私有字段加上Empty
方法。只是我的个人意见! - Dan TaoEnumerable.Empty<T>()
的实现,它与我所写的非常相似。如果需要在各处都使用空列表,可以使用这种方法以节省内存分配和垃圾回收。如果只偶尔需要一个空列表,请使用您的static readonly
。 - Daniel A.A. Pelsmaekerif (list == List.Empty<T>())
的重要代码,则不同的对象可能会成为问题。另外,这种方法如何节省内存分配和垃圾回收呢? - Dan Taostatic readonly IList<T> EmptyList = new T[0]
时,你都会分配另一个 T[0]
对象。如果你使用 n 种不同类型的 T,则将分配 至少 n 个 T[0]
对象,而我的方法将恰好分配 n 个 T[0]
对象。顺便说一句,程序员永远不应该依赖于 list == List.Empty<T>()
(或者 e == Enumerable.Empty<T>()
,因为它们存在相同的问题)。毕竟,Empty<T>()
是一个方法,而方法通常不能保证总是返回相同的值。 - Daniel A.A. Pelsmaeker这个怎么样:
readonly List<T> mylist = new List<T>();
不确定为什么你想要它是只读的;在我能想到的大多数情况下,这并没有太多意义。
IEnumerable<T>
很好用,谢谢。 - David MolesIList
只是一个序列,我们就不需要它了,我们只需使用IEnumerable
。如果您想要任何ICollection
方法,则至少需要ICollection
,如果您想要索引访问,则需要IList
。ICollection<T>
中的修改操作是可选的,这就是为什么有IsReadOnly()
以及为什么Add()
等被记录为抛出NotSupportedException
的原因。 - David Moles