为什么BigInteger在C#中声明为ValueType(struct)?它似乎与声明为引用类型的字符串类型非常相似。
两者都是不可变的(值类型)。两者都可以任意大。
我听到的建议是结构不应超过16个字节。 BigInteger可以比16字节大得多,我认为这会使频繁的操作非常慢,因为它总是按值复制。
答案 0 :(得分:6)
复制BigInteger不会导致复制基础数据。相反,只复制对数据的引用。
由于BigInteger值是不可变的,因此两个或多个值共享公共数据缓冲区是安全的。
BigInteger有两个实例字段:
int _sign
- 可能会告诉它是正值还是负值。uint[] _bits
- 这是对数据缓冲区的引用。 int
是4个字节,引用是8个字节(在64位系统上)。因此,BigInteger的大小≤16字节。
答案 1 :(得分:3)
如果你看一下the source for BigInteger并将其剥离到只有实例级别的字段(那些会计入其大小的东西),那么所有的类都是
public struct BigInteger : IFormattable, IComparable, IComparable<BigInteger>, IEquatable<BigInteger>
{
internal int _sign;
internal uint[] _bits;
}
因此,_sign
有4个字节,uint[]
有4个或8个字节,这取决于你是否在32位或64位系统上,因为数组是引用类型。这为您提供了总共8或12个字节,远低于16个推荐值。 (注意:出于优化原因,CLR会将12字节版本填充为16,使其成为8的倍数)
创建新的BigInteger时,_bits
数组将在两个实例之间共享。因为类型是不可变的(您不能更改_bits
的任何单元格的值),所以两个副本共享数组是安全的。
答案 2 :(得分:3)
以下是BigInteger
:
// For values int.MinValue < n <= int.MaxValue, the value is stored in sign
// and _bits is null. For all other values, sign is +1 or -1 and the bits are in _bits
internal int _sign;
internal uint[] _bits;
所以,一个int
和一个uint[]
,这是一个引用类型。类型本身不能任意增长。它将在x86上为8个字节,在x64上为16个字节(字段为12个字节,填充为4个字节)。
string
和数组是框架中唯一具有不同大小且在运行时特殊的类型。
至于回答这个问题:使用struct
的开销较小。在两个字段上使用class
包装将导致更多的间接性和更多的GC压力,没有充分的理由。此外,BigInteger
在语义上一个值。
答案 3 :(得分:1)
结构的大小只是因为每次从一个函数传递给另一个函数时必须复制整个结构。如果不是复制,没人会关心。
但是,BigInteger
由两部分组成:
实际的结构,是你传递BigInteger
时被复制的部分,而且相当小,而且
每次复制结构时都会复制任意长度但 的位数组。
所以,当你传递BigInteger
时,会发生这种情况:
复制前:
[BigInteger instance 1] ---------> [array of bits]
复制后:
[BigInteger instance 1] ---------> [array of bits]
|
[BigInteger instance 2] ----+
注意总是只有一个位数组。