在 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# 中测试泛型集合的引用相等性是一个愚蠢的想法吗?的主要内容,如果未能解决你的问题,请参考以下文章

C#中ArrayList和泛型集合List方法概述概述

C#定义一个泛型集合类。要求:实现Ienumerable<T>接口,T是值类型,并T取2个类型分别测试。

C#高级编程笔记 Day 5, 9月 13日 (泛型)

类库,委托,as.is,var,泛型集合

泛型约束

C#进阶C# 泛型