3

The "C# 4.0 IN A NUTSHELL" 4th edition book by the Albaharis states on page 249: ". . . calling object.ReferenceEquals guarantees normal referential equality."

So, I decided to test this out.

First I tried value types like this.

 int aa1 = 5;
 int aa2 = aa1;
MessageBox.Show("object.ReferenceEquals(aa1,aa2) is: " + object.ReferenceEquals(aa1, aa2)); 

And just as I expected, the result was false: object.ReferenceEquals(aa1, aa2) is: False

Life was good. Then I tried a mutable reference type like this.

System.Text.StringBuilder sblr1 = new System.Text.StringBuilder();
sblr1.Append("aaa");
System.Text.StringBuilder sblr2 = sblr1;          
MessageBox.Show("object.ReferenceEquals(sblr1,sblr2) is: " + object.ReferenceEquals(sblr1, sblr2)); 

And just as I expected, the result was true object.ReferenceEquals(sblr1, sblr2) is: True

Life was still good. Then I figured that since it is a mutable reference type, then if I change one variable to null, then both should be null. So I tried the following.

System.Text.StringBuilder sblr1 = new System.Text.StringBuilder();
sblr1.Append("aaa");
System.Text.StringBuilder sblr2 = sblr1;
sblr1 = null;
MessageBox.Show("object.ReferenceEquals(sblr1,sblr2) is: " + object.ReferenceEquals(sblr1, sblr2)); 

And I expected them to both be null. But the result I got was False: object.ReferenceEquals(sblr1, sblr2) is: False

Now life was not so good. I thought that if it overrode the memory location of sblr1, then it would be overriding the memory location of sblr2 also.

Then I thought that maybe they were pointing to two different nulls, so I tried this:

System.Text.StringBuilder sblr1 = new System.Text.StringBuilder();
sblr1.Append("aaa");
System.Text.StringBuilder sblr2 = sblr1;
sblr2 = null;
MessageBox.Show("sblr1 == " + sblr1 + " and sblr2 == " + sblr2);

But here, only one was pointing to a null like this. sblr1 == aaa and sblr2 ==

Only one was null.

It was displaying the behavior I'd expect from an immutable reference type like a string object. With a string object, I can do something like this:

string aa1 = "aaX";
string aa2 = "aaX";
MessageBox.Show("object.ReferenceEquals(aa1,aa2) is: " + object.ReferenceEquals(aa1, aa2)); 

And they will both reference the same thing like this. object.ReferenceEquals(aa1, aa2) is: True because "aaX" only gets written to the assembly once.

But if I do this:

string aa1 = "aaX";
string aa2 = "aaX"; 
aa1 = null; 
MessageBox.Show("After aa1 is null(" + aa1 + "), then aa2 is: " + aa2);

Then they point to different things like this: After aa1 is null (), then aa2 is: aaX

That's because string objects are immutable. The memory location doesn't get overriden. Rather, the variable points to a different location in Heap memory where the new value exists. Changing aa1 to null in the above example means that aa1 will point to a different location on the Heap memory.

Why then is the mutable reference type behaving just the same as the immutable reference type?


Edit 4:03PM and 4:08

I've recently tried this:

System.Text.StringBuilder sblr1 = new System.Text.StringBuilder();
sblr1.Append("aaa");

// sblr1 and sblr2 should now both point to the same location on the Heap that has "aaa".
System.Text.StringBuilder sblr2 = sblr1;

System.Text.StringBuilder sblr3 = new System.Text.StringBuilder();
sblr3.Append("bbb");

sblr1 = sblr3;
MessageBox.Show("sblr1 == " + sblr1 + " and sblr2 == " + sblr2 + " and sblr3 == " + sblr3);

Which gave me: sblr1 == bbb and sblr2 == aaa and sblr3 == bbb

That's more like the result I was expecting. I see now, thanks to the comments, that I abscent mindedly expected null to act like a memory location.

4

3 に答える 3

1

sblr1 のメモリ ロケーションをオーバーライドすると、sblr2 のメモリ ロケーションもオーバーライドされると思いました。

これはあなたの誤解です。

これを書くとき:

System.Text.StringBuilder sblr2 = sblr1;

が指すものsblr2と同じ のインスタンスへの参照になるように変数を割り当てています。2 つの変数が同じ参照を指すようになりました。StringBuildersblr1

次に、次のように記述します。

sblr1 = null;

これにより、sblr1変数が null 参照に変更されます。メモリ内のインスタンスをまったく変更していません。

これは、参照が変更可能な型であるかどうかとは関係ありません。参照しているインスタンスではなく、変数を変更しています。

あなたの文字列の例については:

これは、文字列オブジェクトが不変であるためです。メモリの場所は上書きされません

これは実際には真実ではありません。1 つの文字列変数を に設定しているという事実は、実際にnullは文字列が不変であることとは何の関係もありません。それは別の懸念です。

では、可変参照型が不変参照型と同じように動作するのはなぜでしょうか?

あなたが見ている動作は、可変性とは何の関係もありません。これは、すべての参照型 (不変または可変) の標準的な動作です。可変性は別の問題です。

可変性に関する主な問題は次のとおりです。

次のようなクラスがあるとします。

class Foo
{
    public int Bar { get; set; }
}

これを書くと:

Foo a = new Foo();
a.Bar = 42;
Foo b = a;
b.Bar = 54;
Console.WriteLine(a.Bar); // Will print 54, since you've changed the same mutable object

不変型では、変更できないため、これは発生しません。Bar代わりに、不変クラスを作成すると、次のようになります。

class Baz
{
    public Baz(int bar) { this.Bar = bar; }

    public int Bar { get; private set; }
}

次のように書く必要があります。

Baz a = new Baz(42);
Baz b = a;

// This isn't legal now:
// b.Bar = 54;
// So you'd write:
b = new Baz(54); // Creates a new reference

または、クラスが「変更」操作で新しい参照を返すようにすることもできます。つまり、次のようになります。

class Baz
{
    public Baz(int bar) { this.Bar = bar; }

    public int Bar { get; private set; }

    public Baz Alter(int newValue) { return new Baz(newValue); } // May copy other data from "this"
}

次に、次のように記述します。

Baz a = new Baz(42);
Baz b = a.Alter(54); // b is now a new instance

文字列は不変であるため、すべてのメソッドが新しいインスタンスを返すため、既存のコピーを「変更」することstringはできません。

于 2013-04-05T19:20:57.737 に答える
0

これは可変性とは関係ありません。ここに含まれる規則は、すべての参照型で同じです。参照型の非変数 (またはメンバーrefoutまたはコレクション内のスロット) は参照です (当然のことです)。つまり、あるオブジェクトを参照しています。別の参照を参照したり、別の参照が存在する場所 (変数など) を参照したりしません。変数 (またはメンバー、またはコレクションのスロット) に代入すると、その場所にある参照が変更されます。オブジェクトのどの部分も上書きしません (もちろん、割り当てたメンバーがメンバーである場合はそのメンバーを除きます)

コードには と の 2 つの変数がsrbl1ありsrbl2、それぞれが同じ文字列ビルダ オブジェクトへの参照を格納しています。いずれかの変更に割り当てると、それらの参照の 1 つが上書きされます (たとえば、null、または別のオブジェクトへの参照で)。

于 2013-04-05T19:23:21.110 に答える
0

参照を変更するとは、何かが参照するものを変更することです。オブジェクト自体は変更されません。

それを見る 1 つの方法は、整数の配列を想像することです。

int[] foo = new int[] {0, 1, 2, 3, 4, 5};

配列内のアイテムを参照する 2 つのインデックスを作成できます。

int ix = 1;
int iy = ix;

そしてfoo[ix] == foo[iy]

次に を書いた場合でも、インデックスが参照する値を変更したため、 then は真ですfoo[ix] = 42foo[ix] == foo[iy]

しかし、そのようにインデックスを変更するとix = 3ixiyは別のものを参照しています。

参照型はまったく同じように機能します。

を記述するsblr1 = new StringBuilder()と、新しいStringBuilderオブジェクト インスタンスが作成され、それがsblr1ポイントされます。次に と書くと、同じことを指摘してsblr2 = sblr1いるだけです。sblr2そしてsblr1 = null、「sblr1 はもう何も指していません」と言うだけです。インデックスを配列に変更しても、インデックスが作成されているアイテムの値に影響しないのと同様に、参照するアイテムには実際には影響しません。

于 2013-04-05T19:28:25.133 に答える