C# BigInteger是否是不可变的?
在.NET 4 beta 2中,有一个新的Numerics名称空间,带有C# BigInteger是否是不可变的?,c#,.net,immutability,biginteger,fcl,C#,.net,Immutability,Biginteger,Fcl,在.NET 4 beta 2中,有一个新的Numerics名称空间,带有struct biginger。声明它是一个不可变的类型,正如我所预料的那样 但是我对后增量操作符(++)有点困惑。这显然似乎改变了价值观。以下while循环有效: static BigInteger Factorial(BigInteger n) { BigInteger result = BigInteger.One; BigInteger b = BigInteger.One; while (
struct biginger
。声明它是一个不可变的类型,正如我所预料的那样
但是我对后增量操作符(++
)有点困惑。这显然似乎改变了价值观。以下while循环有效:
static BigInteger Factorial(BigInteger n)
{
BigInteger result = BigInteger.One;
BigInteger b = BigInteger.One;
while (b <= n)
{
result = result * b;
b++; // immutable ?
}
return result;
}
静态BigInteger阶乘(BigInteger n)
{
BigInteger结果=BigInteger.One;
BigInteger b=BigInteger.1;
而(b运算符++
和-
是根据正常的++
和-
运算符实现的,因此实际上:
b++;
相当于:
var temp = b;
b = b + 1;
<use temp for the expression where b++ was located>
BigInteger temp=b;
b=temp+1;
因此原始对象没有改变,因此它不会破坏不变性,为了回答问题的新部分,这应该是线程安全的
这与字符串发生的情况相同:
String s1 = s2;
s2 += "More";
// now inspect s1 and s2, they will differ
由于BigInteger是不可变的,因此b++将等同于:
var temp = b;
b = b + 1;
<use temp for the expression where b++ was located>
BigInteger temp=b;
b=temp+1;
执行此操作后,GC将回收temp并释放内存。好的,但是在BigInteger上定义的一元求反运算符呢:
public static BigInteger operator -(BigInteger value)
{
value._sign = -value._sign;
return value;
}
它似乎打破了不变性模式,直接改变了BigInteger对象
b = -b;
实际上,在不返回新对象的情况下就地更改现有的BigInteger
BigInteger b = BigInteger.One;
b++; // immutable ?
在您的示例中,b是一个变量,它只是当前方法堆栈帧中的一个内存插槽。它被初始化为1,b++接受b,创建一个新的BigInteger(具有递增的值)并返回它。变量b现在具有返回的新BigInteger的状态
老实说,在处理引用类型时,不变性作为一个概念要清楚得多,因为堆上有一个内部状态从未改变的对象,所以当一个操作/方法返回一个具有不同状态的新对象时,这是很明显的(例如,可以使用object.ReferenceEquals执行对象引用相等性检查)(对象,对象)
对于值类型,堆上没有对象,只有内存中包含值位的插槽。来自microsoft文档,在他们谈到++之后:
尽管此示例似乎修改了现有对象的值,但事实并非如此。
BigInteger对象是不可变的,这意味着在内部,公共语言运行库实际上创建了一个新的BigInteger对象,并为其分配了一个大于其上一个值的值。然后,该新对象返回给调用者。合理,但它似乎仍然打破了不变性。我将对这个问题稍加编辑。在s++=s2
中有一个可见的赋值。如果你接受b++
也是赋值,也就是b=b+1
。但是++
仍然感觉/看起来像是在变异。好的,除了GC部分。它是一个结构(使用内部数组)。是的,唯一的区别是struct存储在堆栈上,而此类存储在堆中。Ted,你认为对象中的BigInteger字段存储在哪里?它在堆中,对它的引用存储在堆栈上。不,BigInteger是一个结构(值类型),没有指针(引用)这里。@HenkHolterman好吧,指针要么在b中,要么在b指向的结构中,无论如何,某些指针必须更改。@HenkHolterman好的,我给你一个例子,假设你有一个字符串,它是一个值类型,你把它传递给一个函数,如果你查看disassembly,你会看到一个64/32位的值作为参数传递对于函数,因为我们的字符串可能超过64位,我们可以假设我们没有传递字符串,我们传递的是一个指针,一个指向字符串副本的指针,但仍然是一个指针。字符串是引用类型。BigInteger不是。存在比IL代码更好的引用。@HenkHolterman我的错,但我有一个更好的例子,如果将大型结构传递给函数,则即使结构是值类型,也会传递指向该结构的指针。