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#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

Vue和React受控组件的区别小结

《Vue和React受控组件的区别小结》本文主要介绍了Vue和React受控组件的区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录背景React 的实现vue3 的实现写法一:直接修改事件参数写法二:通过ref引用 DOMVu

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

C#实现一键批量合并PDF文档

《C#实现一键批量合并PDF文档》这篇文章主要为大家详细介绍了如何使用C#实现一键批量合并PDF文档功能,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言效果展示功能实现1、添加文件2、文件分组(书签)3、定义页码范围4、自定义显示5、定义页面尺寸6、PDF批量合并7、其他方法

C#下Newtonsoft.Json的具体使用

《C#下Newtonsoft.Json的具体使用》Newtonsoft.Json是一个非常流行的C#JSON序列化和反序列化库,它可以方便地将C#对象转换为JSON格式,或者将JSON数据解析为C#对... 目录安装 Newtonsoft.json基本用法1. 序列化 C# 对象为 JSON2. 反序列化

C#文件复制异常:"未能找到文件"的解决方案与预防措施

《C#文件复制异常:未能找到文件的解决方案与预防措施》在C#开发中,文件操作是基础中的基础,但有时最基础的File.Copy()方法也会抛出令人困惑的异常,当targetFilePath设置为D:2... 目录一个看似简单的文件操作问题问题重现与错误分析错误代码示例错误信息根本原因分析全面解决方案1. 确保

基于C#实现PDF转图片的详细教程

《基于C#实现PDF转图片的详细教程》在数字化办公场景中,PDF文件的可视化处理需求日益增长,本文将围绕Spire.PDFfor.NET这一工具,详解如何通过C#将PDF转换为JPG、PNG等主流图片... 目录引言一、组件部署二、快速入门:PDF 转图片的核心 C# 代码三、分辨率设置 - 清晰度的决定因

C# LiteDB处理时间序列数据的高性能解决方案

《C#LiteDB处理时间序列数据的高性能解决方案》LiteDB作为.NET生态下的轻量级嵌入式NoSQL数据库,一直是时间序列处理的优选方案,本文将为大家大家简单介绍一下LiteDB处理时间序列数... 目录为什么选择LiteDB处理时间序列数据第一章:LiteDB时间序列数据模型设计1.1 核心设计原则

Go之errors.New和fmt.Errorf 的区别小结

《Go之errors.New和fmt.Errorf的区别小结》本文主要介绍了Go之errors.New和fmt.Errorf的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考... 目录error的基本用法1. 获取错误信息2. 在条件判断中使用基本区别1.函数签名2.使用场景详细对

Redis中哨兵机制和集群的区别及说明

《Redis中哨兵机制和集群的区别及说明》Redis哨兵通过主从复制实现高可用,适用于中小规模数据;集群采用分布式分片,支持动态扩展,适合大规模数据,哨兵管理简单但扩展性弱,集群性能更强但架构复杂,根... 目录一、架构设计与节点角色1. 哨兵机制(Sentinel)2. 集群(Cluster)二、数据分片