9

我正在实现一个不可变字典的特殊情况,为了方便实现IEnumerable<KeyValuePair<Foo, Bar>>. 通常会修改字典的操作应该返回一个新实例。

到现在为止还挺好。但是当我尝试为该类编写一个流利风格的单元测试时,我发现我尝试过的两个流利断言库(应该流利断言)都不支持对NotBeSameAs()实现的对象的操作IEnumerable——除非你先强制转换他们到Object.

当我第一次遇到这个问题时,我认为它只是框架中的一个洞,但是当我看到 Fluent Assertions 有同样的洞时,我认为(因为我是 C# 的新手)我可能遗漏了一些关于 C# 集合的概念性内容——当我提交问题时,Should 的作者也暗示了这一点。

显然还有其他方法可以对此进行测试——cast toObject和 use NotBeSameAs(),just useObject.ReferenceEquals等等——但如果有充分的理由不这样做,我想知道那是什么。

4

2 回答 2

1

AnIEnumerable<T>不一定是真实的对象。IEnumerable<T>保证您可以枚举它的状态。在简单的情况下,您有一个像 a 这样的容器类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 并“手动”调用这个对象上的所需函数来公开这些知识。

于 2013-03-13T16:24:48.573 回答
1

此外,Jon Skeet 建议看看 Ted Neward 在 2013 年 2 月发表的这篇 MSDN 文章:

.NET 集合,第 2 部分:使用 C5

不可变(受保护)集合

随着函数式概念和编程风格的兴起,很多重点已经转向不可变数据和不可变对象,这主要是因为不可变对象相对于并发和并行编程提供了很多好处,而且还因为许多开发人员发现不可变对象更容易理解和推理。因此,该概念的推论遵循不可变集合的概念——无论集合中的对象是否不可变,集合本身都是固定的,无法更改(添加或删除)集合中的元素。(注意:您可以在bit.ly/12AXD78的 MSDN 基类库 (BCL) 博客中查看 NuGet 上发布的不可变集合的预览 。)

It describes the use of an open source library of collection goodness called C5. Look at http://itu.dk/research/c5/

于 2013-03-13T16:44:57.043 回答