翻译自 Manju lata Yadav 2019年6月2日 的博文 《Difference Between Struct And Class In C#》,补充了一些内容和示例。

结构体(struct)是类(class)的轻量级版本。结构体是值类型,可用于创建行为类似于内置类型的对象。

比较

结构体和类共享许多特性,但与类相比有以下局限性。

  • 结构体不能有默认构造函数(无参构造函数)或析构函数,构造函数中必须给所有字段赋值。

    public struct Coords
    {
    public double x;
    public double y; public Coords() //错误,不允许无参构造函数
    {
    this.x = 3;
    this.y = 4;
    } public Coords(double x) //错误,构造函数中必须给所有字段赋值
    {
    this.x = x;
    } public Coords(double x) //这个是正确的
    {
    this.x = x;
    this.y = 4;
    } public Coords(double x, double y) //这个是正确的
    {
    this.x = x;
    this.y = y;
    }
    }
  • 结构体是值类型,在赋值时进行复制。

  • 结构体是值类型,而类是引用类型。

  • 结构体可以在不使用 new 操作符的情况下实例化。

    例如:

    public struct Coords
    {
    public double x;
    public double y;
    } static void Main()
    {
    Coords p;
    p.x = 3;
    p.y = 4;
    Console.WriteLine($"({p.x}, {p.y})"); // 输出: (3, 4)
    }
  • 结构体不能继承于另一个结构体或者类,类也不能继承结构体。所有结构体都直接继承于抽象类 System.ValueTypeSystem.ValueType 又继承于 System.Object

  • 结构体不能是基类,因此,结构体不能是 abstract 的,且总是隐式密封的(sealed)。

  • 不允许对结构体使用抽象(abstract)和密封(sealed)修饰符,也不允许对结构体成员使用 protectedprotected internal 修饰符。

  • 结构体中的函数成员不能是抽象的(abstract)或虚的(virtual),重写(override)修饰符只允许重写从 System.ValueType 继承的方法。

  • 结构体中不允许实例属性或字段包含初始值设定项。但是,结构体允许静态属性或字段包含初始值设定项。

    例如:

    public struct Coords
    {
    public double x = 4; //错误, 结构体中初始化器不允许实例字段设定初始值
    public static double y = 5; // 正确
    public static double z { get; set; } = 6; // 正确
    }
  • 结构体可以实现接口。

  • 结构体可以用作 nullable type(即:Nullable<T> 中的 T),对其赋值 null 值,参考【Nullable<T> Struct

什么时候使用结构体或类?

要回答这个问题,我们应该很好地理解它们的差异。

序号 结构体(struct 类(class)
1 结构体是值类型,可以在栈(stack)上分配,也可以在包含类型中内联分配。 类是引用类型,在堆(heap)上分配并垃圾回收。
2 值类型的分配和释放通常比引用类型的分配和释放更节约成本。 大的引用类型的赋值比大的值类型的赋值成本更低。
3 在结构体中,每个变量都包含自己的数据副本(refout 参数变量除外),对一个变量的操作不会影响另一个变量。 在类中,两个变量可以包含同一对象的引用,对一个变量的任何操作都会影响另一个变量。

这样,结构体(struct)只能在确定以下情形时使用:

  • 它在逻辑上表示单个值,比如基本类型(int, double,等等)。
  • 它是不可变的(immutable)。
  • 它不会频繁地装箱和拆箱。

在所有其他情形,应该将类型定义为类(class)。

结构体示例:

struct Location
{
public int x, y;
public Location(int x, int y)
{
this.x = x;
this.y = y;
}
} static void Main()
{
Location a = new Location(20, 20);
Location b = a;
a.x = 100;
Console.WriteLine(b.x);
}

输出将是 20。“b” 的值是 “a” 的副本,因此 “b” 不受 “a.x” 更改的影响。但是在类中,输出将是 100,因为变量 “a” 和 “b” 引用同一个对象。


以下为译者补充

结构体实例与类实例

结构体实例的内存在栈(stack)上进行分配,所占用的内存随声明它的类型或方法一起回收。 这就是在赋值时要复制结构体的一个原因。 相比之下,类实例的内存在堆(heap)上进行分配,当对类实例的所有引用都超出范围时,为该类实例分配的内存将由公共语言运行时自动回收(垃圾回收)。

结构体实例的值相等性

两个结构体实例的比较是基于值的比较,而类实例的比较则是对其引用的比较。

若要确定两个结构体实例中的实例字段是否具有相同的值,可使用 ValueType.Equals 方法。 由于所有结构体都隐式继承于 System.ValueType,因此可以直接在其对象上调用该方法,如以下示例所示:

public struct Person
{
public string Name;
public int Age;
public Person(string name, int age)
{
Name = name;
Age = age;
}
} static void Main()
{
Person p1 = new Person("技术译站", 100);
Person p2;
p2.Name = "技术译站";
p2.Age = 100; if (p2.Equals(p1))
Console.WriteLine("p2 和 p1 有相同的值。"); Console.ReadKey();
}
// 输出: p2 和 p1 有相同的值。

System.ValueTypeEquals 是使用反射实现的,因为它必须能够确定任何结构体中有哪些字段。 在创建自己的结构体时,重写 Equals 方法可以提供特定于你的类型的高效求等算法。

“基于值的相等”这一点和 C# 9.0 中新增的记录(record) 类型具有相似之处,想了解 C# 9.0 可以查看:欢迎来到 C# 9.0

作者 : Manju lata Yadav

译者 : 技术译民

出品 : 技术译站

链接 : 英文原文

C# 中 Struct 和 Class 的区别总结的更多相关文章

  1. C#中struct和class的区别详解

    本文详细分析了C#中struct和class的区别,对于C#初学者来说是有必要加以了解并掌握的. 简单来说,struct是值类型,创建一个struct类型的实例被分配在栈上.class是引用类型,创建 ...

  2. C#中struct和class的区别详解 (转载)

    本文详细分析了C#中struct和class的区别,对于C#初学者来说是有必要加以了解并掌握的. 简单来说,struct是值类型,创建一个struct类型的实例被分配在栈上.class是引用类型,创建 ...

  3. C#中Struct与Class的区别

    class和struct最本质的区别是class是引用类型,而struct是值类型,它们在内存中的分配情况有所区别. 什么是class? class(类)是面向对象编程的基本概念,是一种自定义数据结构 ...

  4. 【zz】C++中struct与class的区别

    转载来源:http://blog.sina.com.cn/s/blog_48f587a80100k630.html C++中的struct对C中的struct进行了扩充,它已经不再只是一个包含不同数据 ...

  5. C++中struct和class的区别 [转]

    一. C++中的struct对C中的struct进行了扩充,它已经不再只是一个包含不同数据类型的数据结构了,它已经获取了太多的功能. struct能包含成员函数吗?   能! struct能继承吗?  ...

  6. C++ 中 struct和class 的区别

    来自:http://hi.baidu.com/pengxiangbobin19890125/blog/item/b05586eee77300212df53411.html   C++ prime  中 ...

  7. c#中struct和class的区别 详细[转]

    转自:http://blog.csdn.net/justlovepro/archive/2007/11/02/1863734.aspx 有这么几点不同: 1.struct 是值类型,class是对象类 ...

  8. C#中struct与class的区别详解

    转自:http://blog.csdn.net/justlovepro/archive/2007/11/02/1863734.aspx 有这么几点不同: 1.struct 是值类型,class是对象类 ...

  9. C++中struct 和 class的区别

    首先,C++中类的定义,从狭义上理解,就是我们使用的class类型.从广义上,类就是定义了一个新的类型和新的作用域,它具有成员函数和成员数据. 而对广义类定义的实现分为两种,一种是使用struct实现 ...

  10. C#经典面试题 C# 中 Struct 与 Class 的区别,以及两者的适用场合

    在一家公司面试时,第一个问题就是问到这个 转载 文章 http://www.cnblogs.com/waitrabbit/archive/2008/05/18/1202064.html  来解释此问题 ...

随机推荐

  1. 实验室外的攻防战 UOJ#180 [树状数组]

    实验室外的攻防战 UOJ#180 [树状数组] 题目 时针指向午夜十二点,约定的日子--2月28日终于到来了.随着一声枪响,伏特跳蚤国王率领着他的跳蚤大军们包围了 \(picks\) 博士所在的实验室 ...

  2. Excel 科学计数法数值转换

    问题场景 如果导出的数据文件后缀为.CSV,一般数值类型的数据超过12位后,单元格的数据就用科学计数法来表示了. 比如身份证号.较长的id,数值会超过12位,而科学计数法表示,不方便查看或操作,很多情 ...

  3. Javascript模块化编程(一):模块的写法 (转)

    Javascript模块化编程(一):模块的写法 原文作者: 阮一峰 日期: 2012年10月26日 随着网站逐渐变成"互联网应用程序",嵌入网页的Javascript代码越来越庞 ...

  4. k8s 辨析 port、NodePort、targetPort、containerPort 区别

    刚接触 k8s 涉及到端口到内容较多,容易混淆,这里整理如下: 目录 nodePort port targetPort containerPort 参考文章 nodePort nodePort 提供了 ...

  5. Java中校验身份证号合法性(真伪),获取出生日期、年龄、性别、籍贯

    开发过程中有用的身份证号的业务场景,那么校验身份证的合法性就很重要了,另外还有通过身份证获取出生日期.年龄.性别.籍贯等信息, 下面是本人在开发中用到的关于校验身份证真伪的工具类,可以直接拿来使用,非 ...

  6. jmeter将上一个接口的返回值作为下一个接口的请求参数

    接口响应结果,通常为HTML.Json格式的数据,对于HTML的响应结果的提取,可以通过正则表达式,XPath提取. 对于Json格式响应结果,可以通过正则表达式.JSON Extractor插件.B ...

  7. centos6.8上安装部署 jhipster-registry

    必备环境:jdk8,git,maven 1.安装nodejs #由于采用编译的方式很容易出现一些意外的惊喜,所以我们这儿直接用yum命令安装 #1.查看nodejs版本(命令中不要加 -y 如果版本不 ...

  8. 基于.NetCore3.1系列 —— 日志记录之初识Serilog

    一.前言 对内置日志系统的整体实现进行了介绍之后,可以通过使用内置记录器来实现日志的输出路径.而在实际项目开发中,使用第三方日志框架(如: Log4Net.NLog.Loggr.Serilog.Sen ...

  9. Shader Graph

    About Shader Graph https://docs.unity3d.com/Packages/com.unity.shadergraph@7.3/manual/index.html uni ...

  10. NGUI 优化

    1. Update Ngui 组件继承关系是  UIWidget : UIRect : MonoBehaviour. 因此由每个组件的独自调用update变更为,由某个更新点,统一调用会效率提升.并且 ...