ReadOnlyCollection 有什么神奇之处吗

发布于 2024-08-04 07:12:06 字数 369 浏览 2 评论 0原文

有了这段代码...

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

我在第二行收到编译错误。我预计会出现运行时错误,因为 ReadOnlyCollection 实现 IList 并且 this[T]中有一个设置器>IList 接口。

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

Having this code...

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

I get a compile error at the second line. I would expect a runtime error since ReadOnlyCollection<T> implements IList<T> and the this[T] have a setter in the IList<T> interface.

I've tried to replicate the functionality of ReadOnlyCollection, but removing the setter from this[T] is a compile error.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

滥情稳全场 2024-08-11 07:12:07

索引器是通过显式接口实现实现的,因此您只需如果您这样做,则能够访问它:

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

The indexer is implemented with explicit interface implementation, so you'll only be able to access it if you do:

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

or

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

Of course, it'll then fail at execution time...

This is entirely deliberate and helpful - it means that when the compiler knows it's a ReadOnlyCollection, the unsupported bits of functionality aren't available to you, helping to divert you away from execution time failure.

It's an interesting and relatively unusual step though, effectively implementing one half of a property/indexer implicitly, and one half explicitly.

Contrary to my previous thoughts, I believe ReadOnlyCollection<T> actually implements the whole indexer explicitly, but also provides a public readonly indexer. In other words, it's something like this:

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 ...; }
}
爱她像谁 2024-08-11 07:12:07

它显式实现 IList.Items,这使其成为非公开的,并且您必须强制转换为接口才能实现其实现,并实现一个新的 this[...] 索引器,该索引器被使用,它只有一个获取访问器。

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

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

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

It implements IList.Items explicitly, which makes it non-public, and you'll have to cast to the interface to reach its implementation, and implements a new this[...] indexer, which is used instead, which only has a get-accessor.

If you cast the collection to IList, your code will compile, but will fail at runtime instead.

Unfortunately I don't know how to do this in C#, since writing an indexer in C# involves using the this keyword, and you can't write this:

T IList<T>.this[int index] { get; set; }
玩物 2024-08-11 07:12:07

没有什么神奇之处,ReadOnlyCollection 只是对其自己的索引器和实现 IList 接口的索引器有不同的实现:

public T Item[int index] { get; }

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

如果您将列表转换为 IList,您将收到运行时错误而不是编译错误:

((IList<int>)b)[2] = 3;

编辑:
要在您自己的类中实现索引器,请使用 this 关键字:

public T this[int index] { get { ... } }

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

There is no magic, the ReadOnlyCollection just have different implementations for it's own indexer and the indexer that implements the IList<T> interface:

public T Item[int index] { get; }

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

If you cast your list to IList<int>, you will get a runtime error instead of the compilation error:

((IList<int>)b)[2] = 3;

Edit:
To implement the indexer in your own class, you use the this keyword:

public T this[int index] { get { ... } }

T IList<T>.this[int index] { get { ... } set { ... } }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文