C#——结构和类问题总结
- 前言
- 一、结构体是什么?
- 1)定义
- 2)特点
- 二、类(对象)是什么?
- 1)定义
- 2)特点
- 三、两者的差异性与选择环境?
- 1)差异性
- 2)选择环境
- 总结
前言
很久没有更新,C#相关的东西了,项目中正好碰到结构体和类对象,在此做梳理总结,对比两个的差异,从而引导出项目中区别使用的地方。
一、结构体是什么?
结构体(struct)是C#中的一种值类型,用于定义一个数据结构,其中可以包含字段、方法、属性、事件、运算符、索引器等成员。
1)定义
public struct Point
{public int X { get; set; }public int Y { get; set; }public Point(int x, int y){X = x;Y = y;}public void Display(){Console.WriteLine($"X: {X}, Y: {Y}");}
}
2)特点
- 值类型:
结构体是值类型,分配在栈上,而不是堆上。当结构体变量被赋值给另一个变量时,实际的数据会被复制,而不是引用。这意味着对一个结构体变量的修改不会影响另一个结构体变量。 - 无继承:
结构体不能从其他结构体或类继承,但是可以实现接口。 - 内存高效
由于结构体在栈上分配内存,因此在处理小型数据对象时,结构体通常比类更高效。 - 默认构造函数:
每个结构体都有一个隐式的无参构造函数,该构造函数会将所有字段初始化为其默认值。你不能定义一个显式的无参构造函数,但可以定义有参数的构造函数。 - 初始化要求:
在使用结构体实例之前,必须初始化所有字段,否则会导致编译错误。
二、类(对象)是什么?
类(class)是C#中的一种引用类型,用于定义对象的模板。它封装了数据和行为,可以包含字段、属性、方法、事件,运算符等成员。类是面向对象编程(OOP)的基础,可以通过继承和多态等特性来实现代码的重用和扩展。
1)定义
public class Person
{public string Name { get; set; }public int Age { get; set; }public Person(string name, int age){Name = name;Age = age;}public void Display(){Console.WriteLine($"Name: {Name}, Age: {Age}");}
}
2)特点
- 引用类型:
类是引用类型,实例化时存储在堆上。当一个类的实例被传递给另一个变量时,两个变量引用的是同一个对象,因此对其中一个变量的修改会影响另一个变量。 - 继承:
类支持继承,可以有一个基类(父类)和多个派生类(子类)。通过继承,子类可以重用父类的代码,并可以重写或扩展父类的行为。 - 多态性:
通过继承和接口,类可以实现多态性,允许使用基类类型的变量来引用派生类的对象,从而实现灵活的代码设计。 - 构造函数:
类可以有一个或多个构造函数,用于在创建对象时初始化对象的状态。如果没有定义构造函数,编译器会提供一个默认的无参构造函数。 - 垃圾回收:
类实例的内存由垃圾回收器管理,当对象不再被引用时,垃圾回收器会自动释放内存。
三、两者的差异性与选择环境?
1)差异性
由上述描述的来看我们不难发现以下几点:
- 类型差异:
结构体是值类型,类是引用类型。我们延伸以下:
a.回收上:值类型脱离域后自动释放,引用类型需要等待GC管理。
b.性能上:结构在栈上内存分配和释放更高效,类在堆上分配和回收内存的开销较大。
c.传递方式上:值类型传递时是数据副本传递,副本修改不影响源数据。引用类型是传递引用,对引用改变源数据也会改变。 - 继承差异:
结构体只能实现接口,无法继承其他结构体。
类能实现接口,也支持继承,可以有基类和派生类。 - 构造差异:
结构体有隐式的无参构造函数,但不能显式定义无参构造函数。在使用结构体实例之前完全初始化所有字段,否则会导致编译错误。
类可以有显式定义的无参构造函数和有参构造函数。可不实例化默认值为null。
2)选择环境
通过上述分析不同后,可对应下面的场景。
选择类:
- 需要引用语义时(多个引用指向同一个实例)。
- 需要继承和多态时。
- 实例的生命周期较长,且大小较大时。
选择结构体:
- 需要值语义时(副本之间相互独立)。
- 数据结构较小且简单时。
- 实例的生命周期较短,且频繁创建和销毁时。
总结
类和结构体在C#中有各自的适用场景。类适用于复杂、需要引用语义的数据结构,而结构体适用于小型、简单且频繁操作的数据结构。了解它们上述的差异和使用场景,可以帮助我们在开发过程中做出更好的设计选择。