使用 YIELD 是返回集合的只读方式吗?
我正在编写一个接口,它有一个我想只读的集合属性。我不希望界面的用户能够修改集合。我发现创建只读集合属性的典型建议是将属性的类型设置为 IEnumerable,如下所示:
private List<string> _mylist;
public IEnumerable<string> MyList
{
get
{
return this._mylist;
}
}
但这并不能阻止用户将 IEnumerable 强制转换回 List 并对其进行修改。
如果我使用 Yield
关键字而不是直接返回 _mylist
,则会阻止我的界面的用户修改集合。我这么认为是因为这样我只是一一返回对象,而不是实际的集合。
private List<string> _mylist;
public IEnumerable<string> MyList
{
get
{
foreach(string str in this._mylist)
{
yield return str;
}
}
}
I'm writing an interface which has a collection property which I want to be read only. I don't want users of the interface to be able to modify the collection. The typical suggestion I've found for creating a read only collection property is to set the type of the property to IEnumerable like this:
private List<string> _mylist;
public IEnumerable<string> MyList
{
get
{
return this._mylist;
}
}
Yet this does not prevent the user from casting the IEnumerable back to a List and modifying it.
If I use a Yield
keyword instead of returning _mylist
directly would this prevent users of my interface from being able to modify the collection. I think so because then I'm only returning the objects one by one, and not the actual collection.
private List<string> _mylist;
public IEnumerable<string> MyList
{
get
{
foreach(string str in this._mylist)
{
yield return str;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这是防止类的用户强制转换回列表并访问成员的合理方法。另一种选择是使用 _mylist.AsReadOnly(),它返回
ReadOnlyCollection
。但是,我建议不要担心用户如何通过转换为其他内部类型来“破坏”您的 API。如果您放置
IEnumerable
的公共 API,这就是最终用户将(或应该)使用的 - 而不是尝试转换为List
。试图阻止用户做一些不适当的事情并破坏你的 API,这样充其量也是有问题的,特别是因为你无法阻止所有不适当的使用。This is a reasonable way to prevent users of your class from casting back to a List and accessing members. Another option is to use _mylist.AsReadOnly(), which returns a
ReadOnlyCollection<T>
.However, I would recommend not worrying about how users can "break" your API by casting to other, internal types. If you put a public API of
IEnumerable<T>
, this is what an end user will (or should) use - not trying to cast to aList<T>
. Trying to prevent a user from doing something inappropriate and breaking your API like this is problematic at best, especially since you can't prevent all inappropriate usages.是的,它是不可改变的。
但是,您应该使用
ReadOnlyCollection
< /a> 相反。例如:
Yes, it is immutable.
However, you should use a
ReadOnlyCollection<string>
instead.For example:
是的,这有效。但这不是唯一的方法。这是在 .NET 3.5 中工作的另一种方法:
取自此 问题它还显示了您可以做到这一点的其他一些方法。
(使用 Google 找到)。
Yes, that works. It's not the only way though. Here's another way that works in .NET 3.5:
Taken from this question which also shows some other ways you could do it.
(Found using Google).
如果使用您的类的代码具有完全信任,则它始终可以反映并访问私有字段。这是相当不礼貌的,但转换返回值也只是稍微好一点。如果用户转换你的财产并破坏状态,那么这是他们自己的错。
直接将列表实例作为 IEnumerable 返回的一个优点是 LINQ 可以优化对 ElementAt() 或 Count() 等方法的访问,而不会违反 IEnumerable 的基本约定(因为这两种方法也可以通过枚举来完成)。
If the code using your class has full trust, it could always Reflect and access the private field anyway. It would be rather impolite, but casting the return value is only marginally better. If a user casts your property and corrupts state, it's their own fault for doing so.
One advantage of returning the list instance directly as IEnumerable is that LINQ can optimize access for methods like ElementAt() or Count(), without violating the fundamental contract of IEnumerable (since either could also be accomplished by enumeration).
是的,生成的序列将是只读的。它还具有延迟执行的优点,因此在某些客户端代码枚举序列中的项目之前,不会真正评估循环(尽管如果在客户端代码尝试枚举内部集合之前更改内部集合,这可能会产生意外的后果) 。
Yes, the resulting sequence will be read-only. It also has the advantage of deferred execution, so the loop won't actually be evaluated until some client code enumerates the items in the sequence (although this can have unexpected consequences if the internal collection is changed before the client code tries to enumerate it).