【发布时间】:2020-12-02 13:52:47
【问题描述】:
C# 中的值类型不能有无参数 ctor,因为 CLR 在创建不带参数的实例时的默认行为是将所有位归零。
假设我有一个用例,我希望有一个类型对基础值强制执行一些不变量,并且这些不变量不允许默认的全零状态。这迫使我使用引用类型。现在假设我做了很多,我的意思是 很多 这种类型的实例。性能至关重要,这些分配加起来会给 GC 带来很大压力。我非常想避免这些分配,首先想到的是使用值类型。但是很可惜,我不能,因为默认值是无效的。
假设该类型满足您对值类型的所有其他要求,即它确实表示单个值,具有值语义,最多占用 16 位。唯一的问题是全零值对于这种类型是无效状态。
如何在不牺牲我的类型约定的不变量的情况下实现我的性能目标?
编辑:
一个非常简单的例子,假设我持有一个 64 位序列以及第一个非零位的索引。
public <struct/class> BitSequence64
{
private long _bits;
private int _firstNonZero;
public IEnumerable<byte> Bytes => ...
// A bunch of helper properties.
public BitSequence64(long value)
{
// Set the _firstNonZero, etc.
...
}
// Methods that allow you to twiddle the bits but maintaining
// the invariant of always having at least one non-zero.
}
显然将_bits 设置为全零是没有意义的,特别是因为_firstNonZero 将指向第一位,这不是非零。有很多这样的单独序列,我非常希望这种类型的依赖者能够安全地使用它,而无需在每次传递给面向公众的 API 时验证它不是 default 值。
【问题讨论】:
-
能否提供一个示例案例(值类型版本)?对于某些类型,对我有用的方法是存储调整后的值,以便字段中的零对于消费者来说实际上不是零值。不过,这是否适用于您的情况取决于您在做什么。
-
您是这些类型的唯一用户,您是为其他团队或客户创建它们吗?
-
你不能用有效的默认值初始化它们吗?
-
例如,假设
_bits == 0x1L是一个合理的(未调整的)默认值。如果您要使用_bits ^ 0x1L进行调整,消费者会将_bits == 0x0L视为第一位非零,而_firstNonZero将是正确的。 -
更通用的解决方案?不,没有什么我能想到的。这实际上取决于给定类型的构成以及您认为该类型的合理默认值。也许这就是为什么这对你来说如此 hacky。我不这么看。我看到了完全适合该领域的领域对象的潜力。
标签: c# performance struct default-constructor invariants