IReadOnlyCollection与ReadOnlyCollection

cog*_*el0 6 .net c# linq

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

我的理解是,应该总是尝试在具体类上返回接口.不会深究其背后的原因,关于那已经有很多事情了.

但是在IReadOnlyCollectionvs 的情况下,ReadOnlyCollection我不确定是否应该遵循该规则.

一个IReadOnlyCollection可以很容易地被铸成一个List......好吧...... 打破ReadOnly了合同所承诺的方面.

ReadOnlyCollection但是不能投入一个List,但它意味着返回一个具体的类.

从长远来看,它真的重要吗?在我看来,在大多数情况下,ReadOnly*/IReadOnly*对象仅由方法或只读属性返回.

因此,即使用户决定将其转换为其他东西(在IReadOnly*对象的情况下)或使用LINQ来创建某种类型的集合(在ReadOnly*对象的情况下),实际上没有办法让类暴露出来ReadOnly*/IReadOnly*对象将接受回来.

那么这里的建议是什么,返回一个IReadOnly*接口或一个具体的ReadOnly*类实例?

Mag*_*nus 10

IReadOnlyCollection<T>List<T>如果底层对象属于该类型,则只能转换为.ReadOnlyCollection<T>例如也实现IReadOnlyCollection<T>.

所以我的建议,返回IReadOnlyCollection<T>,如果你担心调用者会错误地将它转换为它不应该的东西,请确保底层类型是ReadOnlyCollection<T>

public IReadOnlyCollection<User> GetUsers()
{
   return new ReadOnlyCollection<User>();
}
Run Code Online (Sandbox Code Playgroud)


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

  • `但是调用者不会认为因为List <T>实现了IReadOnlyCollection <T>,所以他们可以将它转换为List <T>`为什么他们会假设?_`SqlConnection`实现了`IDisposable`,但我不认为我收到的每个`IDisposable`事物都可以转换为SqlConnection`. (4认同)

Cod*_*ter 7

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

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

public class QueueThing
{
    private List<QueueItem> _cantTouchThis;

    public IReadOnlyCollection<QueueItem> GetQueue()
    {
        return _cantTouchThis;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用AsReadOnly()返回一个ReadOnlyList<T>来自 private的 new List<T>

public class QueueThing
{
    private List<QueueItem> _cantTouchThis;

    public IReadOnlyCollection<QueueItem> GetQueue()
    {
        return _cantTouchThis.AsReadOnly();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在调用者可以随意转换返回的值,他们将无法修改_cantTouchThis成员(当然,当他们要使用反射时除外,但无论如何所有的赌注都将关闭)。

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