c#中class和struct区别

2024-06-20 23:18
文章标签 c# 区别 .net class struct netcore

本文主要是介绍c#中class和struct区别,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C#将数据分为两种:值数据类型和引用数据类型,这两种数据类型存储在内存中的不同的地方:值类型数据存储在栈中,而引用类型数据存储在内存的堆中。 

预备知识

1、内存简介 

Windows使用一个系统:虚拟寻址系统。这个系统的作用是将程序可用的内存地址映射到硬件内存中的实际地址上。其实际结果就是32位的机子上每个进程都可以使用4GB的内存,当然,64位机这个数字就大了去了。这4GB的内存实际上包含了程序的所有的部分:可执行代码,DLL以及程序运行时使用的所有变量的内容。这个4GB的内存称为虚拟地址空间或虚拟内存。为方便,这里成为内存。 

4GB中的每个存储单元都是从零开始向上存储的。要访问存储在内存中的某个空间中的,就必须提供表示该存储单元的一个数字。在高级编程语言中,编译器的一个重要作用就是负责将人们可以理解的变量名称变为处理器可以理解的内存地址。 

2、栈 (stack)

在内存中,有一个区域成为栈,对象成员的值数据类型调用方法时,传递给所有方法的是参数的副本。注意:调用方法时,栈存储的是所有参数的副本,因此,经值类型A传递给函数,A的值是不会变化的。当然,引用类型是会变化的,因为在堆中存储的是引用类型的地址,这在后面会有详细的介绍。 

下面以一个例子来说明栈的工作方式,如下面的代码2

  1. {
  2. int a;
  3. //dosomething;
  4. {
  5. int b;
  6. //dosomething
  7. }
  8. }


首先声明a,在内部的代码块中声明b,然后内部的代码块终止,b就出了作用域,最后a出作用域。所以b的生命周期总是包含在a的生命周期内,在释放变量的时候,其顺序总是和分配内存的顺序是相反的。即:变量的生存周期都是嵌套的。这就是栈的工作方式。 

3、堆 (heap)

栈具有相当高的性能,但是变量的生命周期必须是嵌套的,这个要求在有的时候过于苛刻。我们希望有一种别的方法来分配内存,存储一些数据,并在方法退出的很长一段时间内,这些数据仍然是可用的,这时,就使用堆。 堆是内存中的另外一个区域,我们仍然用一个例子来说明堆的工作方式,如下面代码: 

  1. {
  2. Customer customer1; //栈
  3. customer1= new Customer(); //堆
  4. Customer customer2= new Customer();
  5. //do something
  6. }


首先,声明一个Customer  customer1,在栈上给这个引用分配存储空间。请注意:仅仅是给这个引用分配存储空间,并不是实际的Customer对象。customer1占用4个字节的空间(32位机),来表示Customer对象在内存中的地址。 然后,执行第二行代码,完成以下操作:在堆上分配存储空间,用来存储Customer对象,注意:这里是Customer对像。将变量customer1的值设为分配给Customer对象的内存地址。从这个例子中可以看出,建立引用类型的变量的过程要比建立值类型变量的过程复杂,且不避免的有性能的降低。但是,我们可以将一个引用变量的值赋给另一个引用变量,当一个变量出作用域时,它会从栈中删除,但是对象的数据仍然保留在内存中,直到程序停止。 

这样,我们在将一个引用变量A传递给函数时,仅仅是将变量A的引用传递给了函数,即:仅仅是在栈上分配内存,即变量B两者指向同一个内存地址。因此,当变量B发生变化时,变量A也会发生变化。

1、class 是引用类型,struct是值类型

引用类型的值可以设置为null,即class类型的值可以设置为null而struct类型的值不可以。

因为它是值类型(因为值类型变量直接在Stack中保存了数据,因此在生命周期结束前数据不能被任何形式的销毁,而引用类型变量在Heap中保存数据,所以赋值null其实是将对应在Heap中的数据销毁而不是结束变量的生命周期2)。

  1. struct AStruct
  2. {
  3. int aField;
  4. }
  5. class AClass
  6. {
  7. int aField;
  8. }
  9. class MainClass
  10. {
  11. public static void Main()
  12. {
  13. AClass b = null; // No error.
  14. AStruct s = null; // Error [ Cannotconvert null to 'AStruct'because //it is a value type ].
  15. }
  16. }


同时,值类型和引用类型具备的特点他们分别具备。

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace struct_class
  6. {
  7. class TheClass
  8. {
  9. public int x;
  10. }
  11. struct TheStruct
  12. {
  13. public int x;
  14. }
  15. class TestClass
  16. {
  17. public static void structtaker(TheStruct s)
  18. {
  19. s.x = 5;
  20. }
  21. public static void classtaker(TheClass c)
  22. {
  23. c.x = 5;
  24. }
  25. public static void Main()
  26. {
  27. TheStructa = new TheStruct();
  28. TheClass b = new TheClass();
  29. a.x = 1;
  30. b.x = 1;
  31. structtaker(a);
  32. classtaker(b);
  33. Console.WriteLine( "a.x ={0}", a.x);
  34. Console.WriteLine( "b.x ={0}", b.x);
  35. Console.ReadKey();
  36. }
  37. }
  38. }
  39. //a.x=1
  40. //b.x=5


2、关于初始化

struct可以不使用new关键字初始化,而class必须使用new关键字初始化,但是如果不用new对struct对象进行初始化,将不能调用struct对象的方法,除非对struct中的每个字段进行初始化。

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace struct_class
  6. {
  7. struct MyStruct
  8. {
  9. public int i;
  10. public string j;
  11. public void showMsg()
  12. {
  13. Console.WriteLine( "aaaa");
  14. Console.ReadKey();
  15. }
  16. }
  17. public class TestStruct
  18. {
  19. public static void Main()
  20. {
  21. MyStruct astruct;
  22. //MyStructastruct=new Mystruct();
  23. astruct.i = 1;
  24. astruct.j = "a";
  25. astruct.showMsg();
  26. }
  27. }
  28. }


3、关于继承

class支持继承和多态,Struct不支持. 注意:但是Struct 可以和类一样实现接口

4、关于构造函数

classs可以声明无参构造函数,可以声明析构函数;而struct只能声明带参数构造函数,每个字段都要进行初始化,且不能声明析构函数。因此,struct没有自定义的默认无参构造函数,默认无参构造器只是简单地把所有的值初始它的的0等价值。

这篇关于c#中class和struct区别的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1079542

相关文章

一文解析C#中的StringSplitOptions枚举

《一文解析C#中的StringSplitOptions枚举》StringSplitOptions是C#中的一个枚举类型,用于控制string.Split()方法分割字符串时的行为,核心作用是处理分割后... 目录C#的StringSplitOptions枚举1.StringSplitOptions枚举的常用

MySQL中VARCHAR和TEXT的区别小结

《MySQL中VARCHAR和TEXT的区别小结》MySQL中VARCHAR和TEXT用于存储字符串,VARCHAR可变长度存储在行内,适合短文本;TEXT存储在溢出页,适合大文本,下面就来具体的了解... 目录一、VARCHAR 和 TEXT 基本介绍1. VARCHAR2. TEXT二、VARCHAR

C#自动化实现检测并删除PDF文件中的空白页面

《C#自动化实现检测并删除PDF文件中的空白页面》PDF文档在日常工作和生活中扮演着重要的角色,本文将深入探讨如何使用C#编程语言,结合强大的PDF处理库,自动化地检测并删除PDF文件中的空白页面,感... 目录理解PDF空白页的定义与挑战引入Spire.PDF for .NET库核心实现:检测并删除空白页

C#利用Free Spire.XLS for .NET复制Excel工作表

《C#利用FreeSpire.XLSfor.NET复制Excel工作表》在日常的.NET开发中,我们经常需要操作Excel文件,本文将详细介绍C#如何使用FreeSpire.XLSfor.NET... 目录1. 环境准备2. 核心功能3. android示例代码3.1 在同一工作簿内复制工作表3.2 在不同

C#中通过Response.Headers设置自定义参数的代码示例

《C#中通过Response.Headers设置自定义参数的代码示例》:本文主要介绍C#中通过Response.Headers设置自定义响应头的方法,涵盖基础添加、安全校验、生产实践及调试技巧,强... 目录一、基础设置方法1. 直接添加自定义头2. 批量设置模式二、高级配置技巧1. 安全校验机制2. 类型

Java抽象类Abstract Class示例代码详解

《Java抽象类AbstractClass示例代码详解》Java中的抽象类(AbstractClass)是面向对象编程中的重要概念,它通过abstract关键字声明,用于定义一组相关类的公共行为和属... 目录一、抽象类的定义1. 语法格式2. 核心特征二、抽象类的核心用途1. 定义公共接口2. 提供默认实

C#使用iText获取PDF的trailer数据的代码示例

《C#使用iText获取PDF的trailer数据的代码示例》开发程序debug的时候,看到了PDF有个trailer数据,挺有意思,于是考虑用代码把它读出来,那么就用到我们常用的iText框架了,所... 目录引言iText 核心概念C# 代码示例步骤 1: 确保已安装 iText步骤 2: C# 代码程

C#实现高性能拍照与水印添加功能完整方案

《C#实现高性能拍照与水印添加功能完整方案》在工业检测、质量追溯等应用场景中,经常需要对产品进行拍照并添加相关信息水印,本文将详细介绍如何使用C#实现一个高性能的拍照和水印添加功能,包含完整的代码实现... 目录1. 概述2. 功能架构设计3. 核心代码实现python3.1 主拍照方法3.2 安全HBIT

C#实现SHP文件读取与地图显示的完整教程

《C#实现SHP文件读取与地图显示的完整教程》在地理信息系统(GIS)开发中,SHP文件是一种常见的矢量数据格式,本文将详细介绍如何使用C#读取SHP文件并实现地图显示功能,包括坐标转换、图形渲染、平... 目录概述功能特点核心代码解析1. 文件读取与初始化2. 坐标转换3. 图形绘制4. 地图交互功能缩放

C#使用SendMessage实现进程间通信的示例代码

《C#使用SendMessage实现进程间通信的示例代码》在软件开发中,进程间通信(IPC)是关键技术之一,C#通过调用WindowsAPI的SendMessage函数实现这一功能,本文将通过实例介绍... 目录第一章:SendMessage的底层原理揭秘第二章:构建跨进程通信桥梁2.1 定义通信协议2.2