C# 中 Struct 和 Class 的区别总结
翻译自 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.ValueType,System.ValueType又继承于System.Object。结构体不能是基类,因此,结构体不能是
abstract的,且总是隐式密封的(sealed)。不允许对结构体使用抽象(
abstract)和密封(sealed)修饰符,也不允许对结构体成员使用protected或protected 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 | 在结构体中,每个变量都包含自己的数据副本(ref 和 out 参数变量除外),对一个变量的操作不会影响另一个变量。 | 
在类中,两个变量可以包含同一对象的引用,对一个变量的任何操作都会影响另一个变量。 | 
这样,结构体(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.ValueType 的 Equals 是使用反射实现的,因为它必须能够确定任何结构体中有哪些字段。 在创建自己的结构体时,重写 Equals 方法可以提供特定于你的类型的高效求等算法。
“基于值的相等”这一点和 C# 9.0 中新增的记录(record) 类型具有相似之处,想了解 C# 9.0 可以查看:欢迎来到 C# 9.0。
C# 中 Struct 和 Class 的区别总结的更多相关文章
- C#中struct和class的区别详解
		
本文详细分析了C#中struct和class的区别,对于C#初学者来说是有必要加以了解并掌握的. 简单来说,struct是值类型,创建一个struct类型的实例被分配在栈上.class是引用类型,创建 ...
 - C#中struct和class的区别详解   (转载)
		
本文详细分析了C#中struct和class的区别,对于C#初学者来说是有必要加以了解并掌握的. 简单来说,struct是值类型,创建一个struct类型的实例被分配在栈上.class是引用类型,创建 ...
 - C#中Struct与Class的区别
		
class和struct最本质的区别是class是引用类型,而struct是值类型,它们在内存中的分配情况有所区别. 什么是class? class(类)是面向对象编程的基本概念,是一种自定义数据结构 ...
 - 【zz】C++中struct与class的区别
		
转载来源:http://blog.sina.com.cn/s/blog_48f587a80100k630.html C++中的struct对C中的struct进行了扩充,它已经不再只是一个包含不同数据 ...
 - C++中struct和class的区别 [转]
		
一. C++中的struct对C中的struct进行了扩充,它已经不再只是一个包含不同数据类型的数据结构了,它已经获取了太多的功能. struct能包含成员函数吗? 能! struct能继承吗? ...
 - C++ 中 struct和class 的区别
		
来自:http://hi.baidu.com/pengxiangbobin19890125/blog/item/b05586eee77300212df53411.html C++ prime 中 ...
 - c#中struct和class的区别 详细[转]
		
转自:http://blog.csdn.net/justlovepro/archive/2007/11/02/1863734.aspx 有这么几点不同: 1.struct 是值类型,class是对象类 ...
 - C#中struct与class的区别详解
		
转自:http://blog.csdn.net/justlovepro/archive/2007/11/02/1863734.aspx 有这么几点不同: 1.struct 是值类型,class是对象类 ...
 - C++中struct 和 class的区别
		
首先,C++中类的定义,从狭义上理解,就是我们使用的class类型.从广义上,类就是定义了一个新的类型和新的作用域,它具有成员函数和成员数据. 而对广义类定义的实现分为两种,一种是使用struct实现 ...
 - C#经典面试题  C# 中 Struct 与 Class 的区别,以及两者的适用场合
		
在一家公司面试时,第一个问题就是问到这个 转载 文章 http://www.cnblogs.com/waitrabbit/archive/2008/05/18/1202064.html 来解释此问题 ...
 
随机推荐
- Python 用DataFrame读  存 excel
			
读 代码: import pandas as pd e = r'D:\pywork\12\excel信息表.xlsx' df = pd.DataFrame(pd.read_excel(e)) 存 D. ...
 - 封装Vue Element的table表格组件
			
上周分享了几篇关于React组件封装方面的博文,这周就来分享几篇关于Vue组件封装方面的博文,也好让大家能更好地了解React和Vue在组件封装方面的区别. 在封装Vue组件时,我依旧会交叉使用函数式 ...
 - Windows下nacos单机部分发现的坑
			
一.下载nacos的地址: https://github.com/alibaba/nacos/releases 下载 nacos-server-1.3.2.tar.gz 就好 二.在Window ...
 - ImportError: No module named git
			
问题:ImportError: No module named git 解决:yum install GitPython
 - Centos7 yum安装Python3.6环境,超简单
			
原文链接:https://blog.51cto.com/wenguonideshou/2083301 配置好Python3.6和pip3安装EPEL和IUS软件源 yum install epel-r ...
 - 计算机网络-网络层(2)NAT协议
			
网络地址转换(NAT,Network Address Translation)协议: 本地网络内通信的IP数据报的源与目的IP地址均在子网10.0.0.0/24内:所有离开本地网络去往Internet ...
 - Java多线程_生产者消费者模式2
			
在我的上一条博客中,已经介绍到了多线程的经典案列——生产者消费者模式,但是在上篇中用的是传统的麻烦的非阻塞队列实现的.在这篇博客中我将介绍另一种方式就是:用阻塞队列完成生产者消费者模式,可以使用多种阻 ...
 - url_for函数——快速寻找url
			
我们已经知道,知道了url就可以找到对应的视图函数,那么现在问题来了,如果我们知道了视图函数,要怎么找到url呢?这时候我们就需要url_for函数了. # coding: utf-8from fla ...
 - oracle坑。
			
char(2)的,后面的有一个空格.删不掉.在plsql里可以正常查.写死的sql在程序也可以正常查. 程序用占位符的形式,不能查出来.只能转成to_number select t.*,t.rowid ...
 - [BUUOJ记录] [CISCN 2019 初赛]Love Math & [NESTCTF 2019]Love Math 2
			
主要考察利用已有函数构造危险函数绕过,实现RCE. 进入题目给出源码: <?php error_reporting(0); //听说你很喜欢数学,不知道你是否爱它胜过爱flag if(!isse ...