c# - C# 中字符串情况下引用类型和值类型的区别

标签 c#

好吧,我是 C# 的初学者,我学习了引用类型和值类型的概念。我还了解到,值类型位于堆栈中,而引用类型存储在堆中。然后我们需要手动为引用类型分配内存等等。但我无法理解下面的行为。请指导我。

示例1:

    var arr1 = new int[3] { 1, 2, 3 }; // memory allocated
    var arr2 = arr1; // another variable created but pointing to same memory in Heap
    arr2[0] = 2; // value in array 2 changed
    System.Console.WriteLine("");
    foreach (var item in arr1)
    {
        System.Console.WriteLine(item);
    }
    System.Console.WriteLine("------------");

    foreach (var item in arr2)
    {
        System.Console.WriteLine(item);
    }

输出为:

            arr1: 2,2,3
            arr2: 2,2,3

结论:因为两者都指向相同的内存位置。因此,当 Array 2 中的值更改时,Array1 中的值也会受到影响。到目前为止一切顺利。

现在又多了一种引用类型,那就是字符串。

考虑下面的示例 2:

   var Name = "Mosh";
   var FName = Name;
   FName = "Hello";
   System.Console.WriteLine(Name);
   System.Console.WriteLine(FName);

输出为:

Mosh
Hello

预期输出:

Hello
Hello

由于我更改了 FName 的值,我预计 Name 值也会更改因为两者必须指向相同的内存位置 。这是最简单的问题之一,我是初学者,所以请耐心等待。

最佳答案

在 .Net Framework 中,字符串是不可变的引用类型。

由于字符串没有预定义的内存大小(作为可以存储在堆栈中的值类型),因此它可能会变大(大约 20 亿个 Unicode 字符),并且需要动态内存分配。创建 String 对象时,实际值存储在动态内存(堆)中。

不可变意味着它创建后就不能更改。对字符串的每次更改都会创建一个新字符串。这就是为什么所有字符串操作方法都返回字符串的原因。

Reference types have some overhead on construction and destruction and garbage collection, because they are created on the heap. Value types on the other hand have overhead on method calls (if the data size is larger than a pointer), because the whole object is copied rather than just a pointer. Because strings can be much larger than the size of a pointer, they are designed as reference types. Ref.

在您的情况下:当您将名称分配给 FName 时:FName = Name两个字符串都引用包含字符串 "Mosh" 的同一对象(如代码示例中所示)。在堆中。之后FName已设置为另一个字符串值,它引用存储新字符串 "Hello" 的不同内存位置。名称始终指向存储 "Mosh" 的原始内存位置并保持不变。

当 String 用作更新函数中值的参数时,这种作为值类型的行为不太明显。只要 String 参数不是通过引用提供的,它的原始值就不会改变(参见示例)。

using System;

public class Program
{
    public static void Main()
    {
        var Name = "Mosh";
        var FName = Name;
        Console.WriteLine(Object.ReferenceEquals(Name,FName));

        FName = "Hello";
        System.Console.WriteLine(Name);
        System.Console.WriteLine(FName);
        Console.WriteLine(Object.ReferenceEquals(Name,FName));

        TestFunc(Name);
        System.Console.WriteLine(Name); 

        RefFunc(ref FName);
        System.Console.WriteLine(FName);    
    }

    public static void TestFunc(string test)
    {
        test = "after passing";
    }

    public static void RefFunc(ref string test)
    {
        test = "after passing";
    }
}

关于c# - C# 中字符串情况下引用类型和值类型的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47481890/

相关文章:

c# - 旋转渐变在 WPF 中脱离 Canvas

c# - 如何形成有助于序列化到 c# 类中的有效 XSD

c# - 为什么我得到重复项?

C# Linq Datatable 按日期时间月份分组

c# - 我将如何以 C# 最佳方式打印马提尼玻璃图案

c# - LINQ 按总和值分组

C# 查询 Windows 服务

c# - 编码UI : Why is searching for a cell so slow?

c# - 如何自定义 ".NET FrameworkInitialization Error"?

c# - 使用 GetProcessesByName 是检查进程是否正在运行的最佳方法吗?