SO 上已经有几个类似的问题,但我发现没有一个真正涉及这个特定的主题,所以这里......
我的理解是,应该始终尝试通过具体类返回接口。不会深入探讨其背后的原因,已经有很多关于这方面的事情了。
但是,在
IReadOnlyCollection
与 ReadOnlyCollection
的情况下,我不确定是否应该遵循该规则。
一个
IReadOnlyCollection
可以很容易地转换成 List
,这……好吧……打破了合同承诺的 ReadOnly
方面。
然而 ReadOnlyCollection
不能转换为 List
,但这意味着返回一个具体的类。
从长远来看,这真的重要吗?在我看来,在大多数情况下一个
ReadOnly*/IReadOnly*
对象仅由方法或只读属性返回。
因此,即使用户决定将其转换为其他内容(在
IReadOnly*
对象的情况下)或使用 LINQ 创建某种集合(在 ReadOnly*
对象的情况下),也确实存在暴露 ReadOnly*/IReadOnly*
对象的类不可能接受该返回。
那么这里的建议是什么,返回一个
IReadOnly*
接口还是一个具体的 ReadOnly*
类实例?
IReadOnlyCollection<T>
只能转换为 List<T>
。例如,ReadOnlyCollection<T>
还实现了IReadOnlyCollection<T>
。IReadOnlyCollection<T>
,如果您担心调用者会错误地将其转换为不应该的内容,请确保基础类型是 ReadOnlyCollection<T>
public IReadOnlyCollection<User> GetUsers()
{
return new ReadOnlyCollection<User>();
}
但是返回
IReadOnlyCollection<T>
应该足以让函数的调用者理解它应该是只读的。 ReadOnlyCollection<T>
完全保护您的代码,调用者仍然可以使用反射来访问内部列表并对其进行操作。 你绝对应该尝试让你的公共方法返回接口。
如果您担心类的调用者会强制转换和修改您的内部结构,例如在本示例中,不应从外部触及类的内部队列:
public class QueueThing
{
private List<QueueItem> _cantTouchThis;
public IReadOnlyCollection<QueueItem> GetQueue()
{
return _cantTouchThis;
}
}
AsReadOnly()
返回一个新的 ReadOnlyList<T>
,来自私人 List<T>
:
public class QueueThing
{
private List<QueueItem> _cantTouchThis;
public IReadOnlyCollection<QueueItem> GetQueue()
{
return _cantTouchThis.AsReadOnly();
}
}
现在调用者可以随意转换返回的值,他们将无法修改
_cantTouchThis
成员(当然,当他们要使用反射时除外,但无论如何,所有的赌注都消失了)。
鉴于许多类型可以实现接口,此类方法的用户绝对不应该假设将该方法的返回值转换为任何具体类型是安全的。
微软指南此处指出:
✓ 请使用
(或从ReadOnlyCollection<T>
派生的类),或者在极少数情况下使用ReadOnlyCollection<T>
作为表示只读集合的属性或返回值。IEnumerable<T>
所以,基本上,你应该返回
ReadOnlyCollection<T>
。在其他情况下,它指定接口 IEnumerable
,因此如果它想要接口 IReadOnlyCollection<T>
,它会这样说明。