C# BigInteger是否是不可变的?

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 (

在.NET 4 beta 2中,有一个新的Numerics名称空间,带有
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我的错,但我有一个更好的例子,如果将大型结构传递给函数,则即使结构是值类型,也会传递指向该结构的指针。