龙空技术网

C# 数据结构和算法 :01 数据类型 (一)

启辰8 23

前言:

当前你们对“java资源管理器在哪个文件夹”都比较着重,咱们都想要剖析一些“java资源管理器在哪个文件夹”的相关资讯。那么小编也在网摘上搜集了一些对于“java资源管理器在哪个文件夹””的相关知识,希望小伙伴们能喜欢,我们快快来了解一下吧!

欢迎来到第一章节,在这里你将开始使用C#编程语言的上下文中,与数据结构和算法的奇妙冒险。首先,我们将提供对这门语言的简短介绍。你将了解到它的可能性有多么广泛,在多少场景中你可以应用这门语言,以及一些你可以使用的基础构造。这不是一门C#课程,所以我们不会逐一介绍各种特性,只会提供简短的描述。

本章的剩余部分致力于介绍你可以在应用程序中使用的数据类型,包括内置的和用户定义的。首先,你将学习值类型和引用类型之间的区别是什么。然后,你将学习各种可用的数据类型,从值类型开始。在这里,我们将涵盖整数数值类型、浮点数值类型、布尔类型、Unicode字符、常量、枚举、值元组、结构体类型以及可空值类型。最后,我们将介绍引用类型,包括对象和字符串类型,以及类、记录、接口和委托,还有动态和可空引用类型。

正如你所见,你面前有一段相当长的旅程。然而,如果你能好好掌握基础知识,那么理解本书其余部分所呈现的内容将会容易得多。作为作者的我,为你加油——祝你好运!

在本章中,我们将涵盖以下主题:

• C#作为编程语言

• 基于.NET的控制台应用程序

• 数据类型在值类型和引用类型之间的划分

• 值类型

• 引用类型

C# 作为一种编程语言

作为一名开发者,你可能听说过许多编程语言,包括 C#、Java、C++、C、PHP 和 Ruby。在所有这些语言中,你可以使用各种数据结构,以及实现算法,来解决从基础到复杂的问题。然而,每种语言在实现数据结构和相关算法时都有其特定之处。如前所述,本书仅专注于 C# 编程语言。这也是本节的主要话题。

C# 语言,发音为 C sharp,是一种现代的、通用的、强类型的、面向对象的编程语言,可用于开发各种应用程序,如网络、移动、桌面、分布式和嵌入式解决方案,甚至是游戏!它与各种其他技术和平台协同工作,包括 ASP.NET Core、XAML 和 Unity。因此,当你学习 C# 语言,并且更多地了解数据结构和算法在该编程语言的上下文时,你可以使用这些技能来创建多种类型的软件。你可能会想,这是如何可能的?答案其实非常简单——你会理解各种数据结构是如何工作的,如何实现它们,以及如何应用它们来解决各种问题,使用专门的算法。但让我们回到 C# 语言。

该语言的当前版本是 C# 12。值得一提的是,它在各个版本(包括 2.0、3.0、5.0 和 8.0)中有趣的历史,新功能的增加扩展了语言的可能性。当你查看特定版本的发布说明时,你会看到语言是如何随着时间的推移而改进和扩展,成为开发者的一个强大而方便的解决方案。新功能非常棒,可以显著简化你的工作,并允许你重构代码,使其更短,同时也更容易理解和维护。这是 C# 开发团队所做的伟大工作,你现在可以在编写代码时从中受益。

C# 编程语言的语法与其他语言(如 Java 或 C++)相似。因此,如果你了解这些语言,你应该能够轻松理解用 C# 编写的代码。例如,与前面提到的语言一样,代码由以分号(;)结尾的语句组成。大括号,即 { 和 },用于将语句分组。

有几种类型的语句,包括以下几种:

• 包含 if 和 switch 的选择语句。if 语句允许你根据提供的条件有条件地执行代码。switch 语句使得使用模式匹配来选择要执行的语句列表成为可能。

• 包括 do-while、while、for 和 foreach 的迭代语句。它们与循环相关,并用于在条件满足时多次执行代码的一部分。

• 包含break、continue和goto的跳转语句。它们用于控制循环的执行,例如中断循环或移动到下一次迭代。

• 包括throw、try-catch、try-finally和try-catch-finally的异常处理语句。它们与代码中各个部分可能抛出的异常处理相关。

还有其他语句存在,如lock、yield、checked、unchecked和fixed。在本书接下来的章节中,您将看到一些前面列表中提到的语句在代码示例中,以及相应的解释。

通过许多额外的优秀功能的可用性,如语言集成查询(LINQ),C#语言开发各种应用程序也得到了简化,它允许开发者从各种来源,包括SQL数据库和XML文档,一致地获取数据。还有一些方法可以缩短所需的代码,例如使用Lambda表达式、模式匹配、属性、表达式体成员、记录和字符串插值。值得一提的是自动垃圾回收,它极大地简化了释放内存的任务。

当然,之前提到的解决方案只是在C#开发中可用的功能的一个非常有限的子集。在本书的后续部分,您将看到一些其他功能,以及示例和详细描述。

基于.NET的控制台应用程序

为了保持简单,在阅读这本书时,你将创建许多基于控制台的应用程序,但数据结构和算法也可以用于其他类型的解决方案。这些基于控制台的应用程序将在Microsoft Visual Studio 2022 Community中创建。这个集成开发环境(IDE)是一个全面的解决方案,用于开发各种类型的项目,并配备了众多出色的特性,这些特性简化了你的应用程序的开发和测试。

在启动IDE之后,我们就可以开始创建一个新项目了。创建一个新项目,请按照以下步骤操作:

1. 在主菜单中点击文件 | 新建 | 项目。

2. 在创建新项目窗口的右侧选择控制台应用程序。

3. 输入项目名称(Project name),选择文件存放位置(Location),并输入解决方案名称(Solution name)。然后,点击“下一步”。

4. 在“附加信息”窗口中,将框架版本设置为.NET 8.0(长期支持版),并确保“不使用顶级语句”选项未被选中。如果你准备好了,点击“创建”按钮以自动创建项目并生成必要的文件。

祝贺!你刚刚创建了第一个项目。但里面有什么呢?

让我们来看看“解决方案资源管理器”窗口,它展示了项目的结构。值得一提的是,项目被包含在同名的解决方案中。当然,一个解决方案可以包含不止一个项目,这是开发更复杂应用程序时的常见情况。如果你浏览这本书的GitHub仓库,你可以看到这一点。它包含一个解决方案和超过40个项目。

没有解决方案资源管理器吗?

如果你找不到解决方案资源管理器窗口,你可以通过从主菜单选择视图 | 解决方案资源管理器选项来打开它。同样,你可以打开其他窗口,比如输出或类视图。如果你在视图选项中找不到合适的窗口(例如,C# 交互式窗口),你可以在视图 | 其他窗口节点中找到它。

自动生成的项目包含 Dependencies 元素,该元素展示了项目使用的额外依赖项。值得注意的是,您可以通过从 Dependencies 元素的上下文菜单中选择 Add Project Reference(添加项目引用)、Add Shared Project Reference(添加共享项目引用)或 Add COM Reference(添加 COM 引用)选项轻松添加引用。此外,您还可以使用 NuGet 包管理器安装额外的包,该管理器可以通过从 Dependencies 上下文菜单中选择 Manage NuGet Packages(管理 NuGet 包)来启动。

从头开始编写还是重用现有的包?

在自己编写复杂的模块之前,查看已经可用的包是一个好主意,因为可能已经有适合开发者的包存在。在这种情况下,你不仅可以缩短开发时间,还可以减少引入错误的机会。但是,请检查许可证条件,并确保外部模块是可靠的。

Program.cs 文件包含了C#中的主要代码。你可以通过更改以下默认实现来调整应用程序的行为:

// See  for more informationConsole.WriteLine("Hello, World!");

这个文件的初始内容只包含两行。第一行包含注释,而当程序启动时,另一行会在控制台中写入以下文本:

Hello, World!

看起来修改起来既简单又容易,不是吗?这是真的,而且由于顶级语句的功能,这个文件的默认实现在过去几年里已经发生了显著变化。

通过这些语句,你可以避免定义Program类和Main静态方法的许多代码行,在那里放置简单程序的逻辑。

那么,如果你禁用顶级语句,默认代码会是什么样子呢?让我们来看一看:

namespace GettingStarted{   internal class Program   {     static void Main(string[] args)     {     			Console.WriteLine("Hello, World!");     }   }}

前面的代码包含了在GettingStarted命名空间内Program类的定义。这个类包含了Main静态方法,当应用程序启动时会自动调用这个方法。

在继续之前,让我们先通过文件资源管理器而不是解决方案资源管理器窗口来查看一下项目的结构。这样的结构是一样的吗?

如何打开项目目录

您可以通过在解决方案资源管理器窗口中右键点击项目节点,然后从上下文菜单中选择“在文件资源管理器中打开文件夹”选项来打开包含项目的目录。

首先,你可以看到bin和obj目录,这些是自动生成的。两者都包含Debug和Release目录,这些目录的名称与IDE中设置的配置有关。构建项目后,bin目录的子目录(即Debug或Release)包含net8.0目录,其中包含.exe、.dll和.pdb文件。此外,没有Dependencies目录,但存在.csproj文件,其中包含基于XML的项目配置。同样,基于解决方案的.sln配置文件位于解决方案的目录中。

使用Git忽略一些文件和目录

如果你正在使用版本控制系统,比如Git,你应该忽略bin和obj目录,以及.csproj.user文件。我强烈建议你为各种项目使用版本控制系统,并且频繁地提交和推送更改。如果可能的话,你还可以尝试自动化测试和部署的过程,比如引入持续集成和持续交付(CI/CD)。引入这样的流程可以对你的优秀应用的质量和稳定性产生非常积极的影响,无论它们的类型如何。

既然你已经知道如何为本书中我们将要讨论的例子创建项目,让我们专注于可用的数据类型及其基本分类,并编写一些代码吧!

数据类型的划分

在使用C#语言开发应用程序时,你可以使用各种数据类型,这些类型主要分为两大类,即值类型和引用类型。它们之间的区别非常简单——值类型的变量直接包含数据,而引用类型的变量则仅存储对数据的引用,这些数据位于其他位置。

以下是对这一点的说明:

正如你所见,值类型的变量(显示为A)直接在栈内存中存储其实际值,而引用类型的变量仅在这里存储一个引用。实际值位于堆内存中。因此,有可能有两个或更多的引用类型变量引用同一个值,如前图中的C和D框所示。

小心 - 这是一种简化!

请记住,这在某种程度上是一种简化,因为值类型并不总是存储在栈上。有些情况下,它们会被存储在堆上。如果你对这个话题感兴趣,可以在 上阅读更多关于堆与栈、值类型与引用类型的内容。

当然,在编程时,值类型和引用类型之间的区别非常重要,你应该知道哪些类型属于前面提到的各个组别。否则,你可能会在代码中犯下难以发现的错误。

例如,在使用等于运算符(==)比较两个对象时,你应该小心,因为值类型的两个变量如果它们的数据相等则被认为是相等的,而引用类型的两个变量如果它们引用的是同一个位置则被认为是相等的。

在将引用类型的变量赋值给另一个变量,以及在将引用类型的变量作为参数传递给方法并更新其数据时,你也应该小心。这是因为更改可以反映在引用同一对象的其他变量上。相比之下,在使用值类型时,变量值在作为参数传递给方法、从方法返回结果或赋值给另一个变量时会被复制,因此你只在一个位置修改数据。

值类型和引用类型之间的区别对你来说清楚了吗?如果是的话,让我们继续进入下一节,那里将更详细地描述值类型,并提供一些代码示例。

值类型

为了更好地理解数据类型,让我们首先分析第一组,即值类型。它们进一步分为以下类别:

• 封装数据和功能的结构体,这些结构体又分为以下类别:

内置值类型,也称为简单类型。这些类型分为:

整数数值类型 浮点数值类型 布尔值 Unicode UTF-16字符值元组用户定义的结构类型常量枚举

所有这些组将在本节中描述,从简单的类型开始。

整数

内置值类型的第一个组是整数数值类型,它允许你存储各种整数值。与其他简单类型类似,它们可以作为关键字使用,也可以作为System命名空间中的类型使用。这些类型的不同之处在于使用的字节数以及它们表示的是有符号还是无符号整数值。

想象一个整数值

如果你想更好地可视化一个整数值,你可以找到你周围的例子——这本书的出版年份,你的桌子的腿的数量,以及你的键盘上的键的数量。所有这些都是整数值,比如2024,4和84。是的,我特别为你数了我键盘上的键的数量!

支持的整数数值类型如下:

• 字节(byte 关键字),为8位无符号

• 有符号字节(sbyte),为8位有符号

• Int16(short),为16位有符号

• Uint16(ushort),为16位无符号

• Int32(int),为32位有符号

• UInt32(uint),为32位无符号

• Int64(long),为64位有符号

• UInt64(ulong),为64位无符号

• System.IntPtr(nint),为32位或64位(平台依赖)有符号

• System.UintPtr(nuint),为32位或64位(平台依赖)无符号

正如你所见,数据类型的差异在于存储值的字节数,因此也在于可用值的范围。例如,byte数据类型支持从0到255的值,sbyte从-128到127,short从-32,768到32,767,而uint从0到4,294,967,295。值类型9是一个很大的数字吗?是的,确实是。然而,让我们来看看ulong的范围,它从0到18,446,744,073,709,551,615。

你可以为整型指定以下模式的值:

• 十进制模式:不使用任何前缀 - 例如,45。

• 十六进制模式:使用0x或0X作为前缀 - 例如,0xff代表255。

• 二进制模式:使用0b或0B作为前缀 - 例如,0b1101110代表110。也可以写成0b_0110_1110以提高数字的可读性。

以下是一个示例代码片段:

int a = -20;byte b = 0x0f;uint c = 0b01101110;

我们最后要提到的是任何内置整数类型的默认值。如果我告诉你它是零,你可能不会感到惊讶。

浮点数

第二组内置值类型是浮点数值类型,它允许你存储浮点值。

想象一个浮点值

如果你想更好地想象一个浮点值,你可以用摄氏度测量你当前的体温,用厘米测量你的身高,数一数你钱包里现在有多少钱,或者看看你的电脑处理器频率,以GHz为单位提供。所有这些值都是浮点数 - 例如,36.6、184.8、105.34和1.7。

你可以使用三种浮点数值类型:

• 单精度(float)使用32位 - 例如,1.53f(f或F后缀)

• 双精度(double)使用64位 - 例如,1.53(没有后缀或d/D后缀)

• 十进制(decimal)使用128位 - 例如,1.53M(m或M后缀)

让我们来看一下以下代码:

float temperature = 36.6f;double reading = -4.5178923;decimal salary = 10000.47M;

随着使用的位数从32位到128位的不同,数值的范围和精度显著不同。只需看一下数字:

• float类型存储的数值范围在±1.5×10−45到±3.4×1038之间

• double类型存储的数值范围在±5.0×10−324到±1.7×10308之间

• decimal类型存储的数值范围在±1.0×10-28到±7.9228×1028之间

你可能会惊讶,尽管decimal类型使用的位数是double类型的两倍,但其范围却显著较小。然而,decimal类型对于货币计算是一个很好的选择。

最后,记住任何浮点数类型的默认值是零。

布尔值

关于布尔值,你可以使用布尔类型或者bool关键字。这使得存储一个逻辑值成为可能。它代表两个值中的一个,即真(true)或假(false)。默认值是假(false)。

想象一个布尔值

如果你想可视化一个布尔值,回答以下问题:你现在正在读这本书吗?你至少有5年的经验吗?你已经完成了大学学业吗?你只能用是(true)或否(false)来回答这些问题。不接受其他答案。因此,你可以将这样的回答存储为布尔变量。

让我们来看一下以下代码:

bool isTrue = true;bool first = isTrue || false; // truebool second = isTrue && false; // falsebool third = 50 > 10; // true

有时,使用三值布尔逻辑是必要的,它允许你使用不仅有真(true)和假(false)值,还有无决策值——即空(null)。在这种情况下,你可以从可空布尔类型(bool?)中受益,它也支持三值逻辑。稍后你会学到更多关于可空值类型的知识。

标签: #java资源管理器在哪个文件夹