引入CLR类型(类或接口)的性能成本是什么?

3
尽管 .Net 允许动态调用(例如采用反射、C# 中的 dynamic 关键字),但是当我们使用像 C# 这样的语言时,有时我们感觉有必要采用静态类型,以证明我们的程序是正确的,并且在运行时不会出现类型问题。

有时候,这导致我们引入接口或者基类,感觉它们只是为了向编译器解释,“是的,我知道我传递给该上下文的所有对象都将理解使用参数 Y 调用 invoke 方法 X - 在这里,我将使用接口定义来证明!” (例如——.net 内部使用 IReadChunkBytes 接口来允许将 SteamReadChunkBytes 或 BufferReadChunkBytes 对象传递给某个方法。)

其他时候,我们创建类或类型来服务于其他目的,这些目的并不感觉非常有用处,例如作为具有小附带行为的唯一标识符(有点像枚举值),或者用于保存一组常量等等。

我对更好地理解面对这种设计决策时的“编译时、运行时和其他成本”感兴趣,其中我会问自己,“我应该仅仅为了解决这个问题定义一个新类型或接口吗?” 显然,在每个这样的比较中,成本和收益将各自有两面,但是在一般情况下,我们应该希望看到“在每个这样的比较/讨论中定义新类型”的成本相同。 我们如何量化这些成本?


1
你想要比较哪些替代方案?对我来说,这个问题不够清楚。 - Dan Bryant
3个回答

4

在静态创建新接口或类方面,性能和/或空间成本始终是微不足道的。不要过多考虑这个问题。相比之下,反射和后期绑定可能会导致严重的性能问题。你应该尽可能地使用静态类型。

创建新类或接口所涉及的成本并非性能成本,而是人力成本。以下是添加新类或接口前应考虑的一些因素。无论如何,使用后期绑定或反射可能不会帮助您的程序。这些都是最后的手段。

  • 程序复杂度。虽然这通常不是这种情况,但一个普遍的经验法则是每个类都会增加应用程序的复杂性,从而使其在运行时更难理解、传递给新项目成员、记忆和绘制。更改变得更加困难。
  • 如果你真的觉得一个类是不必要的,也许它确实不是必需的。也许有其他方法来解决你的问题,比如使用更动态的类。也许你可以使用继承或其他技术来减少重复。

+1. 也是关于人力成本的重要说明。 - Alexei Levenkov
我非常喜欢你提到的人力成本问题,但我仍然不同意运行时成本总是可以忽略不计的说法。当你今天面临一个单一的决策时,小问题似乎微不足道,但随着时间的推移,我们和我们的团队成员会做出成百上千次这样的决策,它们最终会累积起来。考虑一下,如果你的决策引入了一个架构模式,为了满足这个模式,就需要创建数百种类型,那会怎么样呢?好吧,也许这也是一个不同的问题。:) 但我们必须能够证明为什么这是一个糟糕的模式... - Tim Lovell-Smith

1
几乎所有东西都有一些运行时成本。唯一的例外是像空白空间这样的东西。原因是几乎所有东西都会在IL映像中记录,包括局部变量名、参数名、常量等。因此,至少会有磁盘成本、虚拟内存空间成本和工作空间成本。
就CPU而言,更多的元数据会减慢程序启动、令牌解析、JIT/NGEN等过程。
但有时添加类型也可能对性能产生积极影响。

0
使用动态类型而不是强类型很可能会导致性能问题。因此,如果您对大多数对象使用dynamic没有问题,那么您可能不需要担心创建静态类型的成本。
顺便提一下:如果您更喜欢动态类型,C#可能不是最适合您工作的语言。并且获取好的示例可能会更困难,因为大多数C#代码都针对强类型对象。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接