Nei*_*len 12 .net c# immutability immutablelist immutable-collections
在不可变性之前,IEnumerable是许多API中的首选接口,因为它具有API对传递对象的实际类型不敏感的优点.
public void DoSomeEnumerationsWithACollection(IEnumerable<Thing> collectionOfThings)
{
foreach (var thing in collectionOfThings) doSomethingWith(thing);
foreach (var thing in collectionOfThings) doSomethingElseWith(thing);
}
Run Code Online (Sandbox Code Playgroud)
当然,至少有两个缺点:
API背后的代码不能依赖collectionOfThings的不变性,可能会遇到"集合修改"异常或遇到其他其他微妙问题.
我们不知道collectionOfThings是真实集合还是简单的延迟查询.如果我们假设它是一个真正的集合,那么我们就不会通过运行多个枚举来降低性能.如果我们假设它是一个延迟查询并且它实际上是一个真实的集合,那么将其转换为本地列表或其他冻结集合会产生不必要的成本,尽管它确实有助于保护我们免受第一个问题的影响(执行"ToList"操作时仍存在竞争条件).显然,我们可以编写少量代码来检查这一点,并尝试做"正确的事情",但这是令人讨厌的额外混乱.
我必须承认,除了使用命名约定之外,我从未找到过令人满意的模式来解决这个问题.尽管存在缺点,但是实用的方法似乎是IEnumerable是传递集合的最低摩擦方法.
现在,随着不可变的收藏,情况得到了很大改善......
public void DoSomeEnumerationsWithACollection(ImmutableList<Thing> collectionOfThings)
{
Run Code Online (Sandbox Code Playgroud)
不再存在收集修改的风险,并且对多个枚举的性能影响没有任何歧义.
但是,我们显然失去了API的灵活性,因为我们现在必须传入一个ImmutableList.如果我们的客户端有其他类型的可枚举不可变集合,则必须将其复制到ImmutableList中才能被使用,即使我们想要做的只是枚举它.
理想情况下,我们可以使用类似的界面
public void DoSomeEnumerationsWithACollection(IImmutableEnumerable<Thing> collectionOfThings)
Run Code Online (Sandbox Code Playgroud)
但是,当然,除了约定之外,接口不能强制执行不可变性等语义.
使用基类可能会起作用
public void DoSomeEnumerationsWithACollection(ImmutableEnumerableBase<Thing> collectionOfThings)
Run Code Online (Sandbox Code Playgroud)
除了它被认为是创建未密封的不可变类的不良形式,以免子类引入可变性.无论如何,这还没有在BCL中完成.
或者我们可以继续在API中使用IEnumerable并使用命名约定来明确我们的代码依赖于传递的不可变集合.
所以...我的问题是在传递不可变集合时哪些模式被认为是最好的?是ImmutableList "新的IEnumerable "一旦我们开始使用不可变性,或是否有更好的办法?
更新
IReadOnlyCollection(由Yuval Itzchakov建议)是对IEnumerable的明显改进,但仍然没有完全保护消费者免受集合中不受控制的变化的影响.值得注意的是,Roslyn代码库大量使用不变性(主要通过ImmutableArray)并且在将这些传递给其他方法时似乎使用显式类型,尽管有几个位置将ImmutableList传递给接受IEnumerable的方法.
经过几年大量使用不可变集合后,我已经决定几乎在所有地方都使用 ImmutableArray 的惯例。这并没有满足 API 灵活性的最初愿望,但在实践中,我很少使用 ImmutableList 或其他类似列表的结构,而且当我这样做时,调用 ToImmutableArray 来通过接口获取数据通常不会有太多开销。
在传递不可变集合时,什么模式被认为是最好的?
我认为你的问题的答案是IReadOnlyCollection<T>
,它将在.NET 4.6中传播。通过传递只读集合,您既可以保持不变性,又可以使用实现该接口的常规集合。
归档时间: |
|
查看次数: |
822 次 |
最近记录: |