C# 中的类与结构:了解差异和性能比较

  1. 介绍

您准备好将您的 C# 编程技能提升到一个新的水平了吗?

然后,您需要了解类和结构之间的区别。作为 C# 编程的两个最基本的构建块,知道如何以及何时使用它们对于创建高效、有效的代码至关重要。

在本文中,我将为您提供了解 C# 中的类和结构的综合指南。我们将首先简要概述一下类和结构是什么。然后,我们将深入探讨它们之间的主要区别,并提供真实示例来帮助说明它们的用法。

但这还不是全部。我们还进行了性能测试,以比较 C# 中类和结构的速度和资源消耗。你将深入了解我们的结果,并了解它们对 C# 开发人员的意义。

那么,让我们开始吧!

II. 什么是类?

类是面向对象编程的构建块,它们是每个开发人员都需要理解的基本概念。在 C# 中,类用于封装数据和行为,允许您创建可重用的模块化代码。

若要在 C# 中创建类,请使用 class 关键字,后跟类的名称。例如:

复制代码
class Person  
{  
    // Class members go here  
}

定义类后,可以使用关键字从中创建对象。例如:new

复制代码
Person john = new Person();

这将创建一个名为 的类的新实例。现在,您可以使用对象访问类的属性和方法。PersonjohnPersonjohn

让我们仔细看看班级内部的内容。可以在类中定义两种主要类型的成员:字段和方法。

字段是存储数据的变量,通常用于表示对象的状态。例如,一个类可能包含人员姓名、年龄和地址的字段:Person

复制代码
class Person  
{  
    string name;  
    int age;  
    string address;  
}

另一方面,方法是执行操作或计算的函数。它们可以访问和操作对象的字段,以及执行其他操作。例如,一个类可能有一个根据其出生日期计算此人的年龄的方法:Person

复制代码
class Person  
{  
    string name;  
    DateTime dateOfBirth;  
      
    public int GetAge()  
    {  
        DateTime today = DateTime.Today;  
        int age = today.Year - dateOfBirth.Year;  
        if (dateOfBirth > today.AddYears(-age))  
            age--;  
        return age;  
    }  
}

在此示例中,该方法使用人员的出生日期字段根据当前日期计算其年龄。GetAge

使用类的主要好处之一是它们允许您封装数据和行为,这意味着您可以隐藏代码的实现细节,并仅公开其他开发人员使用所需的部分。这使您的代码更加模块化且更易于维护。

除了字段和方法之外,还可以定义其他类型的类成员,包括构造函数、属性、事件和嵌套类。其中每一种都有特定的用途,可以帮助您创建更强大、更灵活的代码。

构造函数是用于在创建对象时初始化对象字段的特殊方法。它们与类同名,并使用关键字定义。下面是一个示例:public

复制代码
class Person  
{  
    public string Name;  
      
    public Person(string name)  
    {  
        Name = name;  
    }  
}

在此示例中,该类具有一个构造函数,该构造函数采用参数并将字段设置为该值。当您创建一个新对象时,您可以传入一个名称,该名称将被分配给该字段:PersonnameNamePersonName

复制代码
Person john = new Person("John");

构造函数可以有多个参数,也可以重载。这意味着您可以使用不同的参数列表定义多个构造函数。下面是一个示例:

复制代码
class Person  
{  
    public string Name;  
    public int Age;  
      
    public Person(string name)  
    {  
        Name = name;  
        Age = 0;  
    }  
      
    public Person(string name, int age)  
    {  
        Name = name;  
        Age = age;  
    }  
}

在此示例中,该类有两个构造函数:一个采用参数并将字段设置为 ,另一个同时采用 a 和参数并设置这两个字段。PersonnameAge0nameage

析构函数用于执行对象被销毁时需要执行的任何清理任务。它们是使用符号后跟类名称定义的。下面是一个示例:~

复制代码
class Person  
{  
    public string Name;  
      
    public Person(string name)  
    {  
        Name = name;  
    }  
      
    ~Person()  
    {  
        Console.WriteLine("Person object destroyed.");  
    }  
}

在此示例中,该类具有一个析构函数,该析构函数只是在对象被销毁时将消息写入控制台。您不直接调用析构函数;相反,当不再使用对象时,垃圾回收器会自动调用它们。Person

值得注意的是,您并不总是需要在类中定义析构函数。事实上,在大多数情况下,您根本不需要。析构函数主要用于释放非托管资源,例如文件句柄或数据库连接。如果类不使用任何非托管资源,则无需定义析构函数。

除了析构函数之外,C# 还提供了称为终结器的功能。

终结器与析构函数类似,因为它们用于执行清理任务,但它们的工作方式略有不同。终结器使用符号后跟类名进行定义,垃圾回收器在销毁对象之前调用它们。但是,由于终结器是由垃圾回收器调用的,因此无法准确预测何时调用它们,甚至无法预测它们是否会被调用。出于这个原因,应谨慎使用终结器,并且仅在您别无选择时才使用。~

现在我们已经深入介绍了类,让我们继续讨论一个相关主题:C# 中的结构。

III. 什么是结构体?

结构体是"结构体"的缩写,是 C# 中用户定义的值类型。它类似于类,因为它可以包含数据成员和成员函数(方法),但两者之间存在一些关键差异。

结构和类之间的主要区别之一是结构是值类型,而类是引用类型。这意味着,当您创建结构的实例时,它会在堆栈上分配,而类的实例会在堆上分配。

另一个区别是结构不能继承自基类或用作基类。但是,结构体可以实现接口,就像类一样。

结构体的目的是将相关数据组合成一个单元。这可以使您的代码更有条理、更易于理解,并且在内存使用方面更有效(您将在本文末尾看到性能测试结果。所以,继续阅读)。

下面是 Employee 结构在 C# 中可能是什么样子的示例:

复制代码
struct Employee  
{  
    public string name;  
    public int id;  
    public double salary;  
}

在此示例中,结构包含三个公共数据成员:name(字符串)、id(int)和 payual(双精度)。

在 C# 中,可以使用或不使用"new"关键字创建结构体的实例。

复制代码
// Creating a struct instance with the "new" keyword  
struct Person  
{  
    public string name;  
    public int age;  
}  
  
Person person1 = new Person();  
person1.name = "John";  
person1.age = 30;

在此示例中,我们定义了一个名为"Person"的结构,其中包含两个公共数据成员:"name"(字符串)和"age"(整数)。然后,我们使用"new"关键字创建一个名为"person1"的结构的新实例,并使用点表示法设置其数据成员。

复制代码
// Creating a struct instance without the "new" keyword  
struct Point  
{  
    public int x;  
    public int y;  
}  
  
Point point1;  
point1.x = 5;  
point1.y = 10;

在此示例中,我们定义了一个名为"Point"的结构,其中包含两个公共数据成员:"x"(一个 int)和"y"(一个 int)。然后,我们在不使用"new"关键字的情况下创建一个名为"point1"的结构的新实例,并使用点表示法设置其数据成员。

这是可能的,因为结构是值类型,并且在声明时会自动初始化为其默认值(例如,0 表示整数)。

但是,通常最好使用"new"关键字来创建结构实例,即使您最初不需要设置其数据成员。

IV. C# 中类和结构之间的一些主要区别:

**内存分配:**创建类的实例时,将在堆上分配内存。创建结构体的实例时,会在堆栈上分配内存。这意味着结构的分配和解除分配通常比类更快。

**遗产:**类支持继承,这意味着您可以创建一个新类来继承现有类的数据和行为。结构不支持继承。

**多态性:**类支持多态性,这意味着您可以创建共享公共基类或接口的不同类的对象。结构不支持多态性。

**装箱和拆箱:**装箱是将值类型(如结构)转换为对象引用类型(如类)的过程。取消装箱是将对象引用类型转换回值类型的过程。装箱和拆箱可能很慢,并可能导致内存碎片。类不需要装箱和拆箱,但结构需要。

**易变性:**在 C# 中,可变性是指对象在创建后更改其内部状态的能力。这意味着可以通过添加、删除或更改可变对象的属性、字段或元素来修改可变对象。

另一方面,不可变对象是创建后状态无法更改的对象。

一旦创建了不可变对象,其内部状态就会被固定,任何修改它的尝试都将导致创建一个新对象。由于这个问题很重要,我想我会在另一篇文章中深入解释。

类和结构可以是可变的,也可以是不可变的,这取决于它们的设计方式。

但是,由于结构是值类型,因此默认情况下,它们通常被设计为不可变的。

V. 您可能希望使用类或结构的一些方案:

如果需要支持继承或多态性,或者需要创建将通过引用传递的大型对象,请使用类

如果需要创建一个将按值传递的小对象,或者需要创建一个不会经常变异的对象,请使用结构

由于"EmployeeStruct"的实例是在堆栈上分配的,因此可以比在堆上分配的"EmployeeClass"实例更快地访问和操作它们。

然而,在大多数应用中,这种性能差异通常可以忽略不计。

在检查了类和结构之后,如何从资源消耗和速度方面进行比较?

五、基准测试

对于基准测试,我想到了两种情况。我根据日常生活中经常遇到的情况创造了这两个场景。

测试一

根据第一种情况,需要将应该从服务中获取的数据模型记录在不同的表中。

因此,从服务接收的数据必须映射到两个不同的数据模型。

我通过使用类和结构创建数据模型来测试资源消耗和处理速度。

让我们看看你对结果的看法?

1,000 条记录的测试结果:

包含 10,000 条记录的测试结果。

具有 100,000 条记录的测试结果。

具有 1,000,000 条记录的测试结果。

根据测试结果可以看出,使用 struct 时消耗的资源更少,获得的结果更快。

您可以通过单击此处在我的 GitHub 帐户上访问测试的源代码。

如果你给我的项目一颗星,我会非常高兴。

提前感谢您的好意。

测试二

在第二种情况下,我尝试通过向数组数据结构添加指定数量的值来测试资源消耗和处理速度。

结果如下所示。

从这两个测试的结果来看,我们可以说_结构比类的性能更高。_

总之,了解 C# 中的类和结构对任何开发人员都至关重要。

它们用途广泛、灵活,易于维护和组织代码。

通过利用这些,您可以创建满足项目需求的强大而高效的计划。

如果你喜欢我的文章,请给我一个赞!谢谢

相关推荐
yue0084 小时前
C#理论学习-WinForm实践开发教程总结
开发语言·学习·c#
橙子家5 小时前
Serilog 日志库简单实践(二):控制台与调试 Sinks(.net8)
后端
想不明白的过度思考者5 小时前
Rust——异步递归深度指南:从问题到解决方案
开发语言·后端·rust
陈果然DeepVersion6 小时前
Java大厂面试真题:Spring Boot+Kafka+AI智能客服场景全流程解析(五)
java·spring boot·kafka·向量数据库·大厂面试·rag·ai智能客服
FAFU_kyp6 小时前
Spring Boot 邮件发送系统 - 从零到精通教程
java·网络·spring boot
ConardLi6 小时前
Easy Dataset 已经突破 11.5K Star,这次又带来多项功能更新!
前端·javascript·后端
芒克芒克7 小时前
ssm框架之Spring(上)
java·后端·spring
晨晖27 小时前
SpringBoot的yaml配置文件,热部署
java·spring boot·spring
冒泡的肥皂7 小时前
MVCC初学demo(二
数据库·后端·mysql
追逐时光者7 小时前
一款基于 .NET WinForm 开源、轻量且功能强大的节点编辑器,采用纯 GDI+ 绘制无任何依赖库仅仅100+Kb
后端·.net