在SO上已经有几个类似的问题,但我发现的这些问题都没有真正涉及到这一特定主题,所以这里就是......
我的理解是,应该总是尝试在具体类上返回接口。不会深究其背后的原因,关于那已经有很多事情了。
但是,对于IReadOnlyCollection
与ReadOnlyCollection
的情况,我不确定是否应该遵循该规则。
IReadOnlyCollection
可以很容易地转换为List
,其中...... 打破合同承诺的ReadOnly
方面。< / p>
然而,
ReadOnlyCollection
不能被投射到List
,但这意味着返回一个具体的类。
从长远来看,它真的重要吗?在我看来,在大多数情况下 只能通过方法或只读属性返回ReadOnly*/IReadOnly*
对象。
因此,即使用户决定将其转换为其他内容(在IReadOnly*
对象的情况下),也可以使用LINQ从中创建某种类型的集合(在{{1}的情况下)对象),暴露ReadOnly*
对象的类实际上没有办法接受它。
那么这里的建议是什么,返回ReadOnly*/IReadOnly*
接口或具体的IReadOnly*
类实例?
答案 0 :(得分:9)
IReadOnlyCollection<T>
只能转换为List<T>
。例如ReadOnlyCollection<T>
也实现IReadOnlyCollection<T>
。
所以我的建议,返回IReadOnlyCollection<T>
,如果你担心调用者错误地将它转换为它不应该的东西,请确保基础类型为ReadOnlyCollection<T>
public IReadOnlyCollection<User> GetUsers()
{
return new ReadOnlyCollection<User>();
}
但是返回IReadOnlyCollection<T>
应该足以让函数调用者理解它应该是只读的。
请注意,您永远无法使用ReadOnlyCollection<T>
完全保护您的代码,调用者仍然可以使用反射来访问内部列表并对其进行操作。
在这种情况下唯一的选择是创建一个副本,如果列表并返回。
答案 1 :(得分:2)
你绝对应该尝试让你的公共方法返回接口。
如果您害怕您的班级的调用者将要强制转换和修改您的内部结构,例如在此示例中,不应该从外部触及类的内部队列:
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
成员(当然除非他们要使用反射,但无论如何所有投注都已关闭)。
鉴于许多类型可以实现接口,这种方法的用户绝对不应该假设将方法的返回值强制转换为任何具体类型是安全的。
答案 2 :(得分:1)
Microsoft的指南here声明:
✓使用ReadOnlyCollection,
ReadOnlyCollection<T>
的子类,或者在极少数情况下IEnumerable<T>
使用表示只读集合的属性或返回值。
所以,基本上,你应该返回ReadOnlyCollection<T>
。它在其他情况下指定接口IEnumerable
,因此如果它打算接口IReadOnlyCollection<T>
,它就会这样说。