IReadOnlyCollection 与 ReadOnlyCollection

问题描述 投票:0回答:3

SO 上已经有几个类似的问题,但我发现没有一个真正涉及这个特定的主题,所以这里......

我的理解是,应该始终尝试通过具体类返回接口。不会深入探讨其背后的原因,已经有很多关于这方面的事情了。

但是,在

IReadOnlyCollection
ReadOnlyCollection
的情况下,我不确定是否应该遵循该规则。

一个

IReadOnlyCollection
可以很容易地转换成
List
,这……好吧……打破了合同承诺的
ReadOnly
方面。

然而

ReadOnlyCollection
不能转换为
List
,但这意味着返回一个具体的类。

从长远来看,这真的重要吗?在我看来,在大多数情况下一个

ReadOnly*/IReadOnly*
对象仅由方法或只读属性返回。

因此,即使用户决定将其转换为其他内容(在

IReadOnly*
对象的情况下)或使用 LINQ 创建某种集合(在
ReadOnly*
对象的情况下),也确实存在暴露
ReadOnly*/IReadOnly*
对象的类不可能接受该返回。

那么这里的建议是什么,返回一个

IReadOnly*
接口还是一个具体的
ReadOnly*
类实例?

c# .net linq
3个回答
14
投票
如果底层对象属于该类型,则

IReadOnlyCollection<T>
只能转换为
List<T>
。例如,
ReadOnlyCollection<T>
还实现了
IReadOnlyCollection<T>


所以我的建议是,返回
IReadOnlyCollection<T>
,如果您担心调用者会错误地将其转换为不应该的内容,请确保基础类型是
ReadOnlyCollection<T>

public IReadOnlyCollection<User> GetUsers()
{
   return new ReadOnlyCollection<User>();
}


但是返回

IReadOnlyCollection<T>
应该足以让函数的调用者理解它应该是只读的。
请注意,您永远无法使用
ReadOnlyCollection<T>
完全保护您的代码,调用者仍然可以使用反射来访问内部列表并对其进行操作。
在这种情况下,唯一的选择是创建列表的副本并返回该副本。


10
投票

你绝对应该尝试让你的公共方法返回接口。

如果您担心类的调用者会强制转换和修改您的内部结构,例如在本示例中,不应从外部触及类的内部队列:

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
成员(当然,当他们要使用反射时除外,但无论如何,所有的赌注都消失了)。

鉴于许多类型可以实现接口,此类方法的用户绝对不应该假设将该方法的返回值转换为任何具体类型是安全的。


4
投票

微软指南此处指出:

✓ 请使用

ReadOnlyCollection<T>
(或从
ReadOnlyCollection<T>
派生的类),或者在极少数情况下使用
IEnumerable<T>
作为表示只读集合的属性或返回值。

所以,基本上,你应该返回

ReadOnlyCollection<T>
。在其他情况下,它指定接口
IEnumerable
,因此如果它想要接口
IReadOnlyCollection<T>
,它会这样说明。

© www.soinside.com 2019 - 2024. All rights reserved.