38

我有许多代表各种实体的数据类。

哪个更好:使用泛型和接口编写一个泛型类(例如,打印或输出 XML),还是编写一个单独的类来处理每个数据类?

是否有性能优势或任何其他优势(除了节省我编写单独类的时间)?

4

12 回答 12

60

使用泛型有一个显着的性能优势——你取消了装箱和拆箱。与开发自己的课程相比,这是一次抛硬币(硬币的一侧比另一侧更重)。仅当您认为自己可以胜过框架的作者时,才可以自己动手。

于 2008-09-22T19:33:42.090 回答
22

不仅是的,而且是的。我不相信他们能带来多大的改变。在将一小部分使用 ArrayLists 和 HashTables 的核心代码改写为泛型之后,我们在 VistaDB 中进行了测试。速度提高了 250% 或更多。

阅读我的博客,了解我们对泛型与弱类型集合所做的测试。结果让我们大吃一惊。

我已经开始将许多使用弱类型集合的旧代码重写为强类型集合。我对 ADO.NET 接口最大的了解之一是它们不公开更强类型的数据输入和输出方法。从物体到背面的铸造时间是大批量应用中的绝对杀手。

强类型的另一个副作用是您经常会在代码中发现弱类型的引用问题。我们发现,通过在某些情况下实现结构以避免对 GC 施加压力,我们可以进一步加快代码速度。将此与强输入相结合,以获得最佳速度提升。

有时您必须在 dot net 运行时中使用弱类型接口。尽管尽可能寻找保持强类型的方法。它确实对非平凡应用程序的性能产生了巨大影响。

于 2008-09-23T03:16:02.633 回答
15

从 CLR 的角度来看,C# 中的泛型是真正的泛型类型。泛型类的性能与执行完全相同操作的特定类之间不应该有任何根本区别。这与 Java 泛型不同,Java 泛型更多的是在需要的地方进行自动类型转换或在编译时扩展的 C++ 模板。

这是一篇好论文,有点旧,解释了基本设计: “.NET 公共语言运行时泛型的设计和实现”

如果您为特定任务手动编写类,则您可以通过泛型类型的接口优化需要额外绕行的某些方面。

总之,可能会有性能优势,但我会首先推荐通用解决方案,然后在需要时进行优化。如果您希望实例化具有许多不同类型的泛型,则尤其如此。

于 2008-09-22T19:46:45.833 回答
8

我针对另一个问题对 ArrayList 与 Generic Lists 进行了一些简单的基准测试:Generics vs. Array Lists,你的里程会有所不同,但 Generic List 比 ArrayList 快 4.7 倍。

所以是的,如果您要进行大量操作,装箱/拆箱至关重要。如果您正在做简单的 CRUD 事情,我不会担心。

于 2008-09-22T19:39:01.500 回答
6

泛型是参数化代码和避免重复的方法之一。查看您的程序描述和您编写一个单独的类来处理每个数据对象的想法,我会倾向于泛型。让一个类来处理许多数据对象,而不是许多类做同样的事情,可以提高你的性能。当然,以更改代码的能力衡量的性能通常比计算机性能更重要。:-)

于 2008-09-22T19:44:23.017 回答
4

根据微软的说法,泛型比铸造(装箱/拆箱原语)更快,这是真的。他们还声称泛型提供了比引用类型之间的强制转换更好的性能,这似乎是不真实的(没有人能完全证明这一点)。

Tony Northrup - MCTS 70-536: Application Development Foundation 的合著者 - 在同一本书中陈述如下:

我无法重现泛型的性能优势;然而,根据微软的说法,泛型比使用强制转换更快。在实践中,铸造证明比使用泛型快几倍。但是,您可能不会注意到应用程序的性能差异。(我对超过 100,000 次迭代的测试只用了几秒钟。)所以你仍然应该使用泛型,因为它们是类型安全的。

与引用类型之间的转换相比,我无法通过泛型重现这种性能优势 - 所以我会说性能提升是“假设的”而不是“显着的”。

于 2008-09-22T20:17:04.700 回答
3

如果您将通用列表(例如)与您使用的类型的特定列表进行比较,那么差异很小,JIT 编译器的结果几乎相同。

如果将泛型列表与对象列表进行比较,那么泛型列表有很大的好处——值类型没有装箱/拆箱,也没有引用类型的类型检查。

.net 库中的通用集合类也经过大量优化,您自己不太可能做得更好。

于 2008-09-22T19:40:15.257 回答
3

泛型更快!

我还发现 Tony Northrup 在他的书中写了关于泛型和非泛型性能的错误内容。

我在我的博客上写过这个:http: //andriybuday.blogspot.com/2010/01/generics-performance-vs-non-generics.html

这是一篇很棒的文章,作者比较了泛型和非泛型的性能:

nayyeri.net/use-generics-to-improve-performance

于 2010-01-23T20:38:41.720 回答
2

如果您正在考虑调用某个接口上的方法来完成其工作的泛型类,那将比使用已知类型的特定类慢,因为调用接口方法比(非虚拟)函数调用慢。

当然,除非代码是性能关键过程的缓慢部分,否则您应该关注清晰。

于 2008-09-22T19:44:10.630 回答
2

在泛型集合与拳击等人的情况下,对于像 ArrayList 这样的旧集合,泛型是性能上的胜利。但在绝大多数情况下,这并不是泛型最重要的好处。我认为有两件事会带来更大的好处:

  1. 类型安全。
  2. 自我记录又更具可读性。

泛型促进了类型安全,迫使集合更加同质。想象一下当您期望一个 int 时偶然发现一个字符串。哎哟。

通用集合也更加自我记录。考虑以下两个集合:

ArrayList listOfNames = new ArrayList();
List<NameType> listOfNames = new List<NameType>();

阅读第一行,您可能会认为 listOfNames 是一个字符串列表。错误的!它实际上是存储 NameType 类型的对象。第二个示例不仅强制类型必须是 NameType(或后代),而且代码更具可读性。我马上就知道我需要去查找 TypeName 并通过查看代码来学习如何使用它。

我在 StackOverflow 上看到了很多这样的“x 是否比 y 表现更好”的问题。这里的问题非常公平,事实证明,无论您以何种方式剥猫皮,仿制药都是一种胜利。但归根结底,重点是为用户提供有用的东西。当然,您的应用程序需要能够执行,但它也需要不崩溃,并且您需要能够快速响应错误和功能请求。我认为您可以看到最后两点如何与泛型集合的类型安全和代码可读性相关联。如果是相反的情况,如果 ArrayList 的性能优于 List<>,我可能仍会采用 List<> 实现,除非性能差异很大。

就性能而言(一般而言),我敢打赌,在您的职业生涯中,您会发现这些领域的大部分性能瓶颈:

  1. 数据库或数据库查询设计不佳(包括索引等),
  2. 糟糕的内存管理(忘记调用 dispose、深堆栈、持有对象太久等),
  3. 线程管理不当(线程太多,桌面应用程序的后台线程没有调用 IO 等),
  4. 糟糕的 IO 设计。

这些都不是用单线解决方案解决的。作为程序员、工程师和极客,我们想知道所有很酷的性能小技巧。但重要的是我们要密切关注球。我相信专注于我上面提到的四个领域的良好设计和编程实践将进一步导致远远超过担心小的性能提升。

于 2008-09-22T23:00:43.403 回答
2

也可以在 MSDN 上查看 Rico Mariani 的博客:

http://blogs.msdn.com/ricom/archive/2005/08/26/456879.aspx

Q1:哪个更快?

泛型版本要快得多,见下文。

文章有点旧,但提供了详细信息。

于 2008-09-23T22:54:18.153 回答
0

由于底层实现的变化,您不仅可以取消装箱,而且泛型实现比具有引用类型的非泛型实现要快一些。

原件的设计考虑了特定的扩展模型。这个模型从未真正使用过(无论如何都是一个坏主意),但设计决定迫使一些方法是虚拟的,因此是不可内联的(基于这方面当前和过去的 JIT 优化)。

这个决定在较新的类中得到纠正,但不能在旧类中改变,除非它是潜在的二进制破坏性变化。

此外,由于 ArrayList 的 Enumerator 需要堆分配,因此通过 List<>(而不是 IList<>)上的 foreach 迭代更快。诚然,这确实导致了一个晦涩的错误

于 2009-01-27T00:54:46.423 回答