0

我找到了 Google C# 风格指南和这些要点

对于输入,请尽可能使用最严格的集合类型,例如 IReadOnlyCollection / IReadOnlyList / IEnumerable 当输入应该是不可变的时作为方法的输入。

对于输出,如果将返回容器的所有权传递给所有者,则首选 IList 而不是 IEnumerable。如果不转让所有权,请选择最严格的选项。

关于我无法理解的收藏。

  1. a) 他们对最严格的收集意味着什么?我想它们暗示接口的继承如下:IReadOnlyList<T>inherits IReadOnlyCollection<T>which inherits IEnumerable<T>。那么IEnumerable是最严格的吗?

    b) 最重要的是为什么这很重要?在任何时候任何人都可以将上述集合转换为List<T>并更改内容 - 我认为没有理由选择“最严格的选项”

  2. 他们是否只需要返回接口?这是否意味着我必须始终投向List<T>-IEnumerable<T>这不是误导或打击表现吗?

  3. 他们提到转让所有权。我什么时候想转让所有权,什么时候不想转让?如果我这样做为什么

4

2 回答 2

2

1a) 确实是限制性最强的集合IEnumerable<T>,因为它提供的操作最少。接受尽可能严格的集合作为输入是一种很好的做法,因为它为调用者提供了最大的自由度。它还使您更容易推理您的内部实现,因为您知道集合具有较少的自由度,例如更容易推理不可变集合。

1b) 这不是真的。AnIEnumerable<T>不一定是 List。它也可能是一个自定义集合,恰好实现了接口和许多其他东西。你的演员很可能会失败。

2)如果你返回一个集合,但你仍然拥有它,你想限制调用者只对集合执行你想要的操作。如果要继续检查集合的内容,则不应允许调用者对其进行写入。此外,您可以List<T>从返回类型IEnumerable<T>不带强制转换的方法返回 a。

3)转让所有权基本上意味着您已将集合返回给的调用者现在从现在开始对其负责。您(被调用者)不会关心谁添加到集合中,也不会对再次释放它承担任何责任。在这种情况下,通过将集合公开为其实际类型而不是更具限制性的抽象来授予调用者完全访问权限是合适的。

于 2020-09-01T06:53:27.597 回答
1

如果你传递所有权 - 你基本上是一个工厂,它创建一些集合,其生命周期由调用者控制:

public class A : IA
{
    public IList<int> Create(){return new List<int>();}
}

如果您不传递所有权,例如,您可以自由地为多个调用者提供相同的集合,因此可以以几乎零成本进行缓存:

public class A : IA
{
    private List<int> _someCollection = new List<int>();
    public IEnumerable<int> Create(){return _someCollection; }
}

如果您改为传递 IList,则没有人可以保护此 IList 免受工厂外的意外修改,这将导致缓存损坏。

关于接口...

谷歌鼓励你使用接口而不是具体类型,因为有单元测试和良好的重构实践之类的东西,如果你使用具体类型,这实际上是难以管理的。

例如,如果我想测试这个具体方法调用上没有更多 RAM 的场景,或者在说第 6 个元素之后集合无法枚举,你将如何测试它?或者我希望我的收藏最适合检索前 3 个元素?我只会实现接口:

public class MyOverflowAndPerformantList : IList<int>{/*some bad implementation here*/}

在具体类型的情况下,你实际上会炸毁你的记忆,或者使用一些奇怪的技巧来绕过,因此,这是不切实际的。

于 2020-09-01T06:38:41.203 回答