我正在创建一个体素类型的游戏,我想知道如何存储对象方法。
public class Voxel
{
byte x, y, z;
public virtual void Build(){}
}
public class Flat : Voxel
{
public override void Build(){}
}
如果我用不同的子类体素实例化 100 万次,那么使用更多方法是否会减慢速度? 我应该尽可能地限制类并且不使用任何方法,还是将方法存储在内存中一次?
如果我用不同的子类体素实例化 100 万次,那么使用更多方法是否会减慢速度?
不,事实并非如此。方法不存储在类的实例中。所有方法(静态或非静态)都是类的一部分,而不是实例的一部分。与实例方法的唯一区别是它们有一个隐式的“上下文”/
this
指针作为第一个参数。这一切都由 C# 本身处理。尽管类实例通常有相当多的开销。我们无法真正给出确切的数字,因为这取决于体系结构(32 / 64 位)和一些其他因素(例如对齐)。此外,当您的类具有虚拟/抽象方法时,它需要一个 v 表来定义在哪里可以找到具体方法实现。尽管一个类的 v 表对于每个具体类型也只存在一次。该实例有一个指向该表的指针。非虚方法通过变量类型解析,而虚方法通过使用v表进行动态调度。
所以方法的数量并不重要。正如我所说,当涉及到总体内存开销时,类可能有点棘手。然而,结构要简单得多,因为它们不能派生,也不能有虚方法。因此,结构体实例不包含任何类型信息,而只包含纯数据,无论它有多少方法。
实例方法的工作原理实际上与 C# 的扩展方法非常相似。除了极少数例外,C# 中的几乎所有代码都是静态代码。大多数像泛型这样的异常只需要一个初始的即时编译步骤,并且从那时起也是静态的。
对于大多数体素引擎来说,在实例中存储 x、y、z 位置是很不寻常的。您通常希望尽可能地限制数据。该位置通常是从数组/网格中的位置推断出的属性,并且可以向下传递给必要的方法。 Minecraft 的块类型是类,但每个类都只有一个代表块类型的实例。因此每个块都使用相同的实例来执行虚拟方法魔法。由于结构是值类型,因此您可以用结构包裹一个块,并让结构“拖动”该位置以方便起见。尽管这会深入到具体的设计选择。归根结底,出于各种原因,您通常不想用类实例来表示每个体素。