string
是引用类型,但其作用类似于值。
string a,b;
a=b="test"; //As i understood a and b have to point to the same location in the heap
a="a";
Console.WriteLine("a: {0}, b: {1}",a,b);
结果它打印 a:a,b:test
请解释为什么对a
所做的更改未反映在b
上,因为根据参考类型规则可以预期。
答案 0 :(得分:3)
您没有更改对象a
点,您只是更改变量a
。这对于字符串也不是特别的,你可以用任何类型做到这一点,并获得完全相同的行为。
class Foo
{
private int _i;
public Foo(int i)
{
_i = i;
}
public override string ToString()
{
return _i.ToString();
}
}
Foo a, b;
a=b= new Foo(1);
a=new Foo(2);
Console.WriteLine("a: {0}, b: {1}",a,b);
请参阅我对this question的回答,我深入研究了变量与他们指向的对象之间的差异。
答案 1 :(得分:1)
因为您没有更改a
指向的值 - 您更改了引用本身。例如,这与C中的相同 - 不要想象a = "Hi"
正在改变*a
。
事实上,除了不安全的代码之外,没有办法改变现有的字符串。 .NET中的字符串是不可变的。您只创建新字符串或更改引用,这意味着,string
确实具有值语义,就像任何其他不可变数据类型一样。这是一个设计选择 - 字符串很难,这使它们更简单。
赋值运算符在C#中不可覆盖 - 它总是表示"为标识符"分配值。在string
的情况下,值是字符串的引用,而不是字符串本身。但是在一个本地更改引用并不会更改其他本地的引用。怎么会这样?它不是指向指针的指针。
让我们更好地说明引用类型和值类型之间的区别:
void Main()
{
A a = default(A), b = default(A);
a = b = new A { Number = 42 };
a.Number = 10;
Console.WriteLine(a); // 42
Console.WriteLine(b); // 10
}
public struct A
{
public int Number;
}
现在,A是值类型,因此当我们将b
分配给a
时,我们实际上会复制一份。两个本地人不指向同一个对象。因此,当a.Number
更改为10时,b.Number
将保持为42。
但是,如果您将声明更改为public class A
,则分配仅更改引用的值 - 换句话说,只存在A
的一个实例。然后,a.Number = 10
实际上也会更改b.Number
- 两者在内存中的位置相同。
如果将其与C进行比较,它就好像值本地值是值本身,而引用类型本地是值的指针。所以,像这样:
// Value-type
A a, b;
b.Number = 42;
a = b;
a.Number = 10; // Only the value in a is changed
// Reference-type
A *a, *b;
a = b = new A(42);
a->Number = 10; // Both locals point to the changed value
这与C ++引用的工作方式完全不同 - 在C#中,这些仅限于方法参数。因此,例如,C#中的交换方法如下所示:
void Main()
{
int a = 42, b = 10;
Swap(ref a, ref b);
Console.WriteLine(a); // 10
Console.WriteLine(b); // 42
}
public void Swap(ref int a, ref int b)
{
int x = 0;
SwapI(ref a, ref b, ref x);
}
// No ref locals, so we need a helper method
private void SwapI(ref int a, ref int b, ref int x)
{
x = a;
a = b;
b = x;
}
由于我们切换的参数是ref
,因此它们总是具有引用语义,无论类型是值类型还是引用类型。
答案 2 :(得分:0)
//你把变量搞砸了 - 太棒了!
字符串a,b;
// a =“测试”和 b =“测试”
A = B = “测试”;
//现在 a =“a”且 b 仍然“测试”
一个= “A”;
要让b显示为“a”,您必须将其设置为“a”。设置变量的唯一方法是在变量位于左侧的位置进行声明。因此,为了使b等于“a”,你必须做这样的事情:
在你的最后一行之后 b = a; 。所以你的3行看起来像这样:
A = B = “测试”;
一个= “A”;
//新行
B = A;
现在键入Console.WriteLine(“a:{0},b:{1}”,a,b);
你得到 a:a,b:a