2009-09-11 62 views
11

有了这个代码...有什么魔力约ReadOnlyCollection

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

我在第二条线得到一个编译错误。我期望运行时错误,因为ReadOnlyCollection<T> implements IList<T>this[T]IList<T>接口中有一个setter。

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

回答

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 ...; } 
} 
+0

好的,但我如何使用显式实现复制ReadOnlyCollection的功能。我看不出如何从界面中删除方法或属性。 – 2009-09-11 09:47:04

+0

@EsbenP:你不能从接口中移除一个方法......但是你可以只在引用的静态类型是接口而不是实现接口的类时才可用。 – 2009-09-11 10:14:42

+0

好吧,如果我有两个索引,他们实施的IList的一个明确它的工作原理 牛逼的IList 。这[INT指数] { 得到 { 返回源[指数] } set { throw new NotImplementedException(); } } 公共Ť此[INT指数] { 得到 { 返回源[指数]; } } – 2009-09-11 10:23:12

2

它明确地实现了IList.Items,这使得它是非公开的,你必须转换到接口来实现它,并实现一个新的索引器,它只有一个get-accessor。

如果您将集合转换为IList,您的代码将会编译,但在运行时会失败。

不幸的是,我不知道如何做到这一点在C#中,因为在C#编写索引使用this关键字涉及的,你不能这样写:

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

@Lasse:您可以编写 - 适当的实现。据我所知,问题在于你无法明确地半明确地执行一半。 – 2009-09-11 10:21:01

+0

如果你可以写这个,你不需要,只要抛出一个异常就可以编写setter,然后用getter实现一个public [..]索引器。 – 2009-09-11 11:05:49

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 { ... } } 
+0

这是我的想法,但是当我尝试在我自己的类中实现IList 时,它不会编译 – 2009-09-11 09:52:52

+0

什么是编译错误消息? – thecoop 2009-09-11 10:18:03

+0

@EsbenP:要在类中实现它,语法与文档中显示的签名不同。请参阅上面的修改。 – Guffa 2009-09-11 13:37:28