1

我一直在读一本书并遇到一个声明,泛型允许程序员在使用例如时避免装箱和拆箱Stack

我认为这并不完全正确,因为堆栈(不是通用的)可以只保存引用类型变量,然后只有强制转换,没有装箱。

编辑:AFAIK,装箱只涉及到对象转换的值类型。这是正确的还是我错过了什么?

4

2 回答 2

3

如果您有一个Stack<SomeReferenceType>没有(取消)装箱的情况,那么仅仅是因为引用永远不需要装箱。引用是类型在 .NET 中工作的“正常”方式——object毕竟是引用类型。

编辑:您澄清的问题清楚地表明您在谈论Stack. 你说这个变体不需要装箱和拆箱引用类型是正确的,因为引用类型永远不会被装箱(并且确实不能被装箱)。同样正确的是,如果您将 的子类的实例object放入 中Stack,那么当您取出该项目并尝试使用该实例的一个方面(这对所有objects 并不通用),那么您将需要转换为子类。

请注意(对于引用类型)虽然我们在object概念上谈到“强制转换”,但这并不对应于实际操作;向上转型(对象或任何其他超类)是免费的。机器需要在向下转换中验证向下转换是否有效。Stack因此,仅用引用类型的实例填充 的非泛型变体是有效的;仅在从 the 中提取Stack 转换为更具体的类型时才会发生开销。

为什么你应该更喜欢通用集合。

尽管(向下)铸造相当便宜,但它不是免费的。即使对于引用类型,如果您需要再次提取值,预计泛型集合的性能会略微优于它们的非泛型对应物。但是,即使您(像往常一样)对几个 CPU 周期不感兴趣,通用集合也更可取,因为它们可以帮助您更快地发现错误:如果您不小心将错误类型的项目添加到非通用列表中,您在提取和使用之前不会收到警告,也不会看到错误该值可能会更晚(甚至永远不会)并且在不同的代码文件甚至不同的程序集中。调试此类错误确实很麻烦,特别是如果您的代码有一堆层并且错误不在直接访问集合的层中。

相比之下,如果您尝试添加不正确类型的值,则通用集合甚至不会编译。即使您需要实现类型不安全的接口并且编译器无法捕获错误,您仍然InvalidCastException具有在将项目添加到集合时抛出an 的优势(接近错误的根本原因)而不是在提取之后(远离错误的根本原因)。代码中会有错误,您希望快速且廉价地找到它们,而不是在看似无关的代码中出现奇怪的异常。

实际上,不再使用非泛型集合的唯一原因是与需要使用它们的遗留 API 进行互操作。

于 2011-03-25T09:58:49.543 回答
1

问题是Stack该类将您放入其中的对象存储为object. 这意味着,每次您将某些东西放入堆栈时,它都会被装箱到一个对象中,并且每次您想在堆栈中的对象上使用时,您都需要再次将其拆箱,以获得正确的类型。

于 2011-03-25T09:57:54.023 回答