为什么字符串类型的行为类似于值类型?

时间:2018-10-05 07:04:46

标签: c# boxing value-type reference-type

我对参考类型感到非常困惑。我搜索了一下,发现字符串类型是引用类型。不是吗?

我的问题是:

我将一个字符串变量复制到另一个变量,并更改了第一个变量的值,但是第二个变量的值仍然相同。我不明白这个问题。即使字符串的类型是引用类型,第二个也不改变。我也尝试了装箱方法,但无法获得结果。

我读了这篇文章In C#, why is String a reference type that behaves like a value type?,但是我仍然感到困惑。

这是我的代码:

        string my_text1 = "My text 1";
        string my_text2 = my_text1;

        my_text1 = "My text 2";
        Console.WriteLine("First text --> " + my_text1); // It prints My text 2
        Console.WriteLine("Second text -->" + my_text2); // It prints My text 1(I want it prints "My text 2" too)

        string text_1 = "Example 1";
        object text_2 = text_1;

        text_1 = "Example 2";
        Console.WriteLine("First example --> " + text_1); // It prints Example 2
        Console.WriteLine("Second example -->" + text_2);// It prints Example 1

3 个答案:

答案 0 :(得分:4)

分配是影响变量的动作。变量本身是独立的。值和引用类型之间的重要区别是 data 是存储在变量本身中还是存储在其他地方(并且变量仅包含引用)。

因此,在分配变量时,您可以更改该变量的内容 1 。就其本身而言,这不会对任何其他变量产生可见影响。

变异数据时,您经常会注意到值类型和引用类型之间的区别。在这里,差异是很明显的,因为当您更改值类型的数据时,您是通过特定的变量来完成的,而您正在更改的是该变量的数据副本。而当您将数据更改为引用类型时,则对数据进行了更改,引用同一数据副本的所有变量对他们来说都是可见的更改。

但是,由于string没有任何(没有反射技巧或不安全的代码)可变字段或变异方法,因此您永远无法使用string变量来观察这种变异。


1 此处是指局部变量和字段。其他形式的赋值(例如分配给属性)可以运行任意代码,因此它们当然也可能具有其他明显的副作用。

答案 1 :(得分:3)

因为字符串是不可变的引用类型。

不可变类型是一种对象,其数据在创建后不能更改。不可变的字符串有很多好处。它提高了运行时效率和安全性(进程无法通过注入某些东西来更改字符串)。您可以read对其进行详细说明。

而且,字符串是引用类型的原因是,它们可能很大,需要存储在堆中。详细信息here

您可以使用可变的StringBuilder。

StringBuilder my_text1 = new StringBuilder("My text 1");
StringBuilder my_text2 = new StringBuilder("My text 2");

my_text1 = my_text2;
Console.WriteLine("First text --> " + my_text1); 
Console.WriteLine("Second text -->" + my_text2);

在上面的示例中,两个表达式都将获得“我的文本2”。

答案 2 :(得分:0)

就像Damien_The_Unbeliever指出的那样,赋值总是会更改该变量,并且不会影响以前的变量。

将以下示例与类一起考虑

class Program
{
    static void Main(string[] args)
    {
        Foo my_text1 = new Foo("My text 1");
        Foo my_text2 = my_text1;

        my_text1 = new Foo("My text 2");
        Console.WriteLine("First text --> " + my_text1); // It prints My text 2
        Console.WriteLine("Second text -->" + my_text2); // It prints My text 1

        Foo text_1 = new Foo("Example 1");
        object text_2 = text_1;

        text_1 = new Foo("Example 2");
        Console.WriteLine("First example --> " + text_1); // It prints Example 2
        Console.WriteLine("Second example -->" + text_2);// It prints Example 1
    }
}

class Foo
{
    private readonly string _name;

    public Foo(string name)
    {
        _name = name;
    }

    public override string ToString()
    {
        return _name;
    }
}

字符串不能完全以这种方式工作,但是它使您了解Damien_The_Unbeliever的含义

如果您希望变量充当参考,则应添加ref关键字

string my_text1 = "My text 1";
ref string my_text2 = ref my_text1;

my_text1 = "My text 2";
Console.WriteLine("First text --> " + my_text1); // It prints My text 2
Console.WriteLine("Second text -->" + my_text2); // It prints My text 2