有这个代码...
var b = new ReadOnlyCollection<int>(new[] { 2, 4, 2, 2 });
b[2] = 3;
我在第二行收到编译错误。我预计会出现运行时错误,因为ReadOnlyCollection<T>
实现IList<T>
并且接口中this[T]
有一个设置器IList<T>
。
我试图复制 ReadOnlyCollection 的功能,但从中删除 setterthis[T]
是一个编译错误。
有这个代码...
var b = new ReadOnlyCollection<int>(new[] { 2, 4, 2, 2 });
b[2] = 3;
我在第二行收到编译错误。我预计会出现运行时错误,因为ReadOnlyCollection<T>
实现IList<T>
并且接口中this[T]
有一个设置器IList<T>
。
我试图复制 ReadOnlyCollection 的功能,但从中删除 setterthis[T]
是一个编译错误。
索引器是通过显式接口实现实现的,因此您只有在执行以下操作时才能访问它:
IList<int> b = new ReadOnlyCollection<int>(new[] { 2, 4, 2, 2 });
b[2] = 3;
或者
var b = new ReadOnlyCollection<int>(new[] { 2, 4, 2, 2 });
((IList<int>)b)[2] = 3;
当然,它会在执行时失败......
这完全是经过深思熟虑和有用的——这意味着当编译器知道它是 aReadOnlyCollection
时,您将无法使用不受支持的部分功能,从而帮助您避免执行时间故障。
这是一个有趣且相对不寻常的步骤,隐式有效地实现了属性/索引器的一半,而显式地实现了一半。
与我之前的想法相反,我相信ReadOnlyCollection<T>
实际上明确地实现了整个索引器,但也提供了一个公共的只读索引器。换句话说,它是这样的:
T IList<T>.this[int index]
{
// Delegate interface implementation to "normal" implementation
get { return this[index]; }
set { throw new NotSupportedException("Collection is read-only."); }
}
public T this[int index]
{
get { return ...; }
}
它显式地实现了 IList.Items,这使它成为非公开的,并且您必须强制转换为接口才能实现它,并实现一个新的 this[...] 索引器,它被用来代替,它只有一个获取访问器。
如果您将集合转换为 IList,您的代码将编译,但会在运行时失败。
不幸的是,我不知道如何在 C# 中执行此操作,因为在 C# 中编写索引器涉及使用this
关键字,并且您不能这样编写:
T IList<T>.this[int index] { get; set; }
没有魔法,ReadOnlyCollection
只是它自己的索引器和实现IList<T>
接口的索引器有不同的实现:
public T Item[int index] { get; }
T IList<T>.Item[int index] { get; set; }
如果您将列表转换为IList<int>
,您将收到运行时错误而不是编译错误:
((IList<int>)b)[2] = 3;
编辑:
要在您自己的类中实现索引器,请使用this
关键字:
public T this[int index] { get { ... } }
T IList<T>.this[int index] { get { ... } set { ... } }