9

在 .NET 4 beta 2 中,新的 Numerics 命名空间带有 struct BigInteger. 正如我所料,文档指出它是一种不可变类型。

但是我对后增量运算符 ( ++) 有点困惑。这肯定会改变价值。以下 while 循环有效:

static BigInteger Factorial(BigInteger n)
{
    BigInteger result = BigInteger.One;
    BigInteger b = BigInteger.One;

    while (b <= n)
    {
        result = result * b;
        b++;  // immutable ?
    }
    return result;
}

这就是 MSDN 关于增量运算符的说法:

因为 BigInteger 对象是不可变的,所以 Increment 运算符创建一个新的 BigInteger 对象,其值比由 value 表示的 BigInteger 对象大一。因此,重复调用 Increment 可能会很昂贵。

一切都很好,如果我不得不使用,我会理解的, b = b++但显然++它本身就足以改变一个值。

有什么想法吗?

4

5 回答 5

14

运算符++--是按照正常的+-运算符实现的,因此实际上:

b++;

相当于:

var temp = b;
b = b + 1;
<use temp for the expression where b++ was located>

现在,正如评论的那样,这似乎打破了不变性,但事实并非如此。

相反,您应该查看此代码:

var temp = b;
b = BigInteger.op_Add(b, 1); // constructs a new BigInteger value
<use temp ...>

这将在内存中留下两个对象,一个是原始的 BigInteger 值,另一个是现在由 b 引用的新对象。您可以轻松地检查以下代码是否会发生这种情况:

var x = b;
b++;
// now inspect the contents of x and b, and you'll notice that they differ

所以原始对象没有改变,因此它不会破坏不变性,并且要回答问题的新部分,这应该是线程安全的。

这与字符串发生的情况相同:

String s1 = s2;
s2 += "More";
// now inspect s1 and s2, they will differ
于 2009-10-28T09:00:00.903 回答
3

由于 BigInteger 是不可变的,因此 b++ 将等同于:

BigInteger temp=b;
b=temp+1;

此操作后,临时由 GC 回收并释放内存。

于 2009-10-28T09:05:31.570 回答
0
BigInteger b = BigInteger.One;

b++;  // immutable ?

在您的示例中, b 是一个变量,它只是当前方法堆栈帧中的一个内存槽。它被初始化为 One,b++ 获取 b,创建一个新的 BigInteger(具有递增的值)并返回它。变量 b 现在具有来自返回的新 BigInteger 的状态。

老实说,在处理引用类型时,不变性作为一个概念要清晰得多,因为堆上有一个内部状态永远不会改变的对象,所以当一个操作/方法返回一个具有不同状态的新对象时,这很明显(例如,你可以使用 object.ReferenceEquals(object, object) 进行对象引用相等性检查。

对于值类型,堆上没有对象,只有内存中的插槽包含作为值的位。

于 2019-03-22T13:55:44.040 回答
-1

来自微软文档,在他们谈论 ++ 之后:
虽然这个例子似乎修改了现有对象的值,但事实并非如此。
BigInteger 对象是不可变的,这意味着在内部,公共语言运行时实际上创建了一个新的 BigInteger 对象并为其分配一个比其先前值大一的值。然后将这个新对象返回给调用者。

于 2020-04-05T15:55:24.010 回答
-1

好的,但是 BigInteger 上定义的一元否定运算符呢:

public static BigInteger operator -(BigInteger value)
{
    value._sign = -value._sign;
    return value;
}

它似乎打破了不变性模式并直接改变 BigInteger 对象。所以

b = -b;

实际上在不返回新对象的情况下更改了现有的 BigInteger。

于 2019-03-22T13:31:35.813 回答