ReadOnlyCollection有什么神奇之处吗?

时间:2009-09-11 09:06:20

标签: .net interface readonly-collection

拥有此代码......

var b = new ReadOnlyCollection<int>(new[] { 2, 4, 2, 2 });
b[2] = 3;

我在第二行遇到编译错误。我期望发生运行时错误,因为ReadOnlyCollection<T>实现了IList<T>,而this[T]IList<T>接口中有一个setter。

我试图复制ReadOnlyCollection的功能,但是从this[T]删除setter是一个编译错误。

3 个答案:

答案 0 :(得分:16)

indexer是通过显式接口实现实现的,因此如果您这样做,您将只能访问它:

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;

当然,它会在执行时失败......

这是完全有意识和有帮助的 - 这意味着当编译器知道它是ReadOnlyCollection时,您无法使用不受支持的功能,从而帮助您远离执行时间失败。

这是一个有趣且相对不寻常的步骤,有效地隐式地实现了属性/索引器的一半,并且明确地实现了一半。

与我之前的想法相反,我认为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 ...; }
}

答案 1 :(得分:2)

它显式地实现了IList.Items,这使得它非公开,你必须强制转换到接口以实现它的实现,并实现一个新的this [...]索引器,它被用来代替,只有一个get-accessor。

如果将集合强制转换为IList,则代码将编译,但在运行时将失败。

不幸的是我不知道如何在C#中执行此操作,因为在C#中编写索引器涉及使用this关键字,并且您不能这样写:

T IList<T>.this[int index] { get; set; }

答案 2 :(得分:1)

没有魔力,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 { ... } }