在 C# 中测试泛型集合的引用相等性是一个愚蠢的想法吗?
Posted
技术标签:
【中文标题】在 C# 中测试泛型集合的引用相等性是一个愚蠢的想法吗?【英文标题】:Is testing generic collections for referential equality in C# a silly idea? 【发布时间】:2013-03-01 14:04:41 【问题描述】:我正在实现一个不可变字典的特殊情况,为方便起见,它实现了IEnumerable<KeyValuePair<Foo, Bar>>
。通常会修改字典的操作应该返回一个新实例。
到目前为止一切顺利。但是当我尝试为该类编写一个流利风格的单元测试时,我发现我尝试过的两个流利断言库(Should 和Fluent Assertions)都不支持对实现 @ 的对象的NotBeSameAs()
操作987654327@ -- 除非您先将它们转换为 Object
,否则不会。
当我第一次遇到此问题时,我认为这只是框架中的一个漏洞,但当我看到 Fluent Assertions 有相同的漏洞时,我认为(因为我是一个相对较新的人到 C#)我可能会遗漏一些关于 C# 集合的概念——当我提交问题时,我应该 implied as much 的作者。
显然还有其他方法可以测试这一点——转换为Object
并使用NotBeSameAs()
,只需使用Object.ReferenceEquals
,无论如何——但如果有充分的理由不这样做,我想知道那是什么是。
【问题讨论】:
你看过 MS 不可变集合吗,顺便说一句? nuget.org/packages/Microsoft.Bcl.Immutable @JonSkeet 嗯。你向我们展示了多么好的一面。谢谢。 任何类型都是Object
,为什么需要强制转换?
@Jodrell -- 你需要转换它,因为框架是根据扩展方法实现的,如果你不转换它,你会得到一个更具体的 IEnumerable
扩展方法,它不像Object
的不太具体的那个,不支持NotBeSameAs()
操作。
@JonSkeet 看起来很棒,但许可证似乎禁止在生产代码中使用它? (另外,我最初的问题仍然存在——我很想将不可变集合用于内部实现,但我仍然希望围绕它们的更有限的包装对象来实现 IEnumerable。)
【参考方案1】:
IEnumerable<T>
不一定是真实对象。 IEnumerable<T>
保证您可以枚举它的状态。在简单的情况下,您有一个像 List<T>
这样的容器类,它已经物化了。然后你可以比较两个列表的地址。但是,您的 IEnumerable<T>
也可能指向一系列命令,一旦您枚举就会执行。基本上是一个状态机:
public IEnumerable<int> GetInts()
yield return 10;
yield return 20;
yield return 30;
如果你把它保存在一个变量中,你就没有一个可比较的对象(一切都是一个对象,所以你有……但它没有意义):
var x = GetInts();
您的比较仅适用于物化(.ToList()
或 .ToArray()
)IEnumerables,因为这些状态机已被评估并且它们的结果已保存到集合中。所以是的,这个库实际上是有意义的,如果你知道你已经实现了 IEnumerables,你需要通过将它们转换为 Object 并“手动”调用这个对象上所需的函数来公开这些知识。
【讨论】:
【参考方案2】:除了 Jon Skeet 的建议之外,请查看 Ted Neward 于 2013 年 2 月发表的 MSDN 文章:
.NET Collections, Part 2: Working with C5
不可变(受保护)集合
随着功能概念的兴起 和编程风格,很多重点已经转向不可变数据 和不可变对象,主要是因为不可变对象提供了很多 相对于并发和并行编程的好处,而且 因为许多开发人员发现不可变对象更容易理解 和理由。因此,该概念的推论遵循该概念 不可变集合的概念——不管是否 集合内的对象是不可变的,集合本身是 已修复且无法更改(添加或删除) 收藏。 (注意:您可以看到不可变集合的预览 在 MSDN 基类库 (BCL) 博客中的 NuGet 上发布 bit.ly/12AXD78.)
它描述了一个名为 C5 的开源收藏库的使用。 看http://itu.dk/research/c5/
【讨论】:
我看了一下 C5,但我遇到了很多奇怪的转换问题,试图让它与System.Collections.Generic
互操作。 (在某些时候,如果我对开箱即用的集合感到沮丧,也许我会再试一次,并将这些问题变成 *** 问题......)以上是关于在 C# 中测试泛型集合的引用相等性是一个愚蠢的想法吗?的主要内容,如果未能解决你的问题,请参考以下文章