首页 / 教程列表 / C#程序设计基础(入门篇) / 值类型和引用类型

值类型和引用类型

1808 更新于: 2021-07-16 读完约需 9 分钟

概述

在前面章节我们详细学习了C#的常用数据类型,包括《数字类型》、《字符和字符串》、《布尔类型》等。

C#语言中主要把数据类型分为两类:值类型和引用类型

  • 值类型包括简单类型(如int、float、bool和char)、enum类型、struct类型和Nullable值类型。
  • 引用类型包括类类型、接口类型、委托类型和数组类型。

值类型如struct, 引用类型如class,本节我们将深入学习C#语言的这两种数据类型。

值类型

在C#语言中,如果数据类型在其自己的内存空间中保存数据值,那么这样的数据类型就是值类型。也就是说,这些数据类型的变量直接包含值。

C#的所有值类型均隐式派生自System.ValueType

下面我们以一个简单的值类型变量作为示例:

int i = 100;

这里声明了一个变量名为i的值类型变量,并为其赋值等于100,那么系统将值100存储在为变量i分配的内存空间中。我们假定分配的内存地址为0x3258984,变量i在内存中的存储如下图所示:

系统内置的值类型有:

  • bool
  • byte
  • char
  • decimal
  • double
  • enum
  • float
  • int
  • long
  • sbyte
  • short
  • struct
  • uint
  • ulong
  • ushort

传递值类型变量

当将值类型变量从一个方法传递到另一个方法时,系统将在另一个方法中创建变量的单独副本。如果变量值在一个方法中被改变了,它不会影响另一个方法中变量的值,如下示例:

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 50;
            Console.WriteLine(i);
            Change(i);
            Console.WriteLine(i);
        }

        static void Change(int x)
        {
            x =  60;
            Console.WriteLine(x);
        }
    }
}

输出结果为:

50
60
50

关于方法,将在后续的章节中详细了解,为了本节内容的完整性作,这里作了解。

以上示例中,Main方法中的变量i最初的值为50,随后我们调用Change()方法,并在该方法内部对方法参数x的值进行了修改,从输出的结果可以看到:Main()方法中变量i的值没未随之改动,仍然是50

引用类型

在C#语言中,与值类型不同的是,引用类型不直接存储它的值。相反,它存储存储值的地址。换句话说,引用类型包含一个指向另一个存储数据的内存位置的指针。

我们再定义一个引用类型的变量,如下:

string hello = "Hello World";

变量hello在内存中的分配如下图:

如上图所示,系统在内存中中随机分配了两块内存空间。其中变量hello地址为0x230086,存储的值为0x202020,它实际上存储的是另一块内存的地址。而内存在地址0x202020中存储的是变量hello的真实字符串值。因此,我们可以看出,引用类型存储的是一个内存的引用地址而不是其真实的值。

传递引用类型变量

当将引用类型变量从一个方法传递到另一个方法时,系统将不会在另一个方法中创建变量的单独副本,而是使用这个变量的引用地址。如果变量值在一个方法中被改变了,它会影响另一个方法中变量的值,如下示例:

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var customer1 = new Customer
            {
                Name = "Rector"
            };
            Console.WriteLine(customer1.Name);
            Change(customer1);
            Console.WriteLine(customer1.Name);
        }

        static void Change(Customer customer2)
        {
            customer2.Name = "Tom";
        }

    }

    class Customer
    {
        public string Name { get; set; }
    }
}

以上示例中,我们在Main方法中声明引用类型变量customer1,并设置其Name属性的最初值为Rector,随后调用Change()方法,并在该方法内部对方法参数customer2Name属性值进行了修改。方法被调用后,从输出的结果可以看到:Main()方法中变量customer1Name属性值被改动了。

Change(Customer customer2)方法传递的是customer1的内存地址。即:customer1customer2指向同一个内存地址,所以,在修改customer2时会影响到customer1的属性值。

String是一种引用类型,但它是不可变的。这意味着一旦我们分配了一个值,它就不能被更改。如果我们改变一个字符串值,编译器会在内存中创建一个新的字符串对象,并将一个变量指向新的内存位置。因此,将字符串值传递给另一个方法时将在内存中创建一个新变量,方法中值的任何变化都不会影响原始值,如下所示:

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            string name1 = "Rector";
            Console.WriteLine(name1);
            Change(name1);
            Console.WriteLine(name1);
        }

        static void Change(string name)
        {
            name = "Tom";
            Console.WriteLine($"Inner name:{name}");
        }

    }
}

版权声明:本作品系原创,版权归码友网所有,如未经许可,禁止任何形式转载,违者必究。

发表评论

登录用户才能发表评论, 请 登 录 或者 注册