练习 - 调用 .NET 类的方法

已完成

无论你是否意识到,从你的第一个“Hello, World!”应用程序开始,你一直在调用 C# 方法。 该应用程序使用 Console 类的 WriteLine() 方法来显示“Hello, World!”消息。

但是,并非所有类和方法都通过相同的方式来实现。 本单元介绍使用 .NET 类库中的方法时需要了解的一些最常见的变量。 重点将介绍如何查找和使用文档来更好地了解每种方法的详细信息。

如何调用 .NET 类库中的方法

通过以前调用 Console.WriteLine() 方法的经验,你应已了解基本知识:

  • 首先键入类名。 在本例中,类名为 Console
  • 添加成员访问运算符,即 . 符号。
  • 添加方法的名称。 在本例中,方法的名称为 WriteLine
  • 添加方法调用运算符,该运算符是一组括号 ()
  • 最后,指定传递给方法的参数(如果有),将其用方法调用运算符的括号括起来。 在这种情况下,可以指定希望 Console.WriteLine() 方法写入控制台的文本(例如 "Hello World!")。

(可选)根据开发者设计和实现给定方法的方式,可能还需要执行以下操作:

  • 传递其他值为输入参数。
  • 接受返回值。

在下一单元中,你将了解如何将输入值传递给方法,以及如何使用方法将值返回到调用例程。

虽然某些方法的调用方式与 Console.WriteLine() 的相同,但 .NET 类库中还有一些方法需要使用其他调用方式。

准备编码环境

本模块包括编码活动,它们会引导你完成生成和运行示例代码的过程。 建议使用 Visual Studio Code 作为开发环境来完成这些活动。 使用 Visual Studio Code 来完成这些活动将帮助你在供全球专业人员使用的开发人员环境中更舒适地编写和运行代码。

  1. 打开 Visual Studio Code。

    可以使用 Windows“开始”菜单(或等效资源 [对于其他 OS])打开 Visual Studio Code。

  2. 在 Visual Studio Code 的“文件”菜单上,选择“打开文件夹”。

  3. 在“打开文件夹”对话框中,导航到 Windows 桌面文件夹。

    如果使用了其他文件夹位置来保存代码项目,可以改用该文件夹位置。 对于此训练,重要的是要有一个容易找到和记住的位置。

  4. 在“打开文件夹”对话框中,选择“选择文件夹”。

    如果看到一个询问是否信任作者的安全对话框,请选择“是”。

  5. 在 Visual Studio Code 的“终端”菜单上,选择“新终端”。

    请注意,“终端”面板中的命令提示符显示当前文件夹的文件夹路径。 例如:

    C:\Users\someuser\Desktop>
    

    注意

    如果你在自己的电脑上工作,而不是在沙盒或托管环境中工作,并且你已经完成此 C# 系列中的其他 Microsoft Learn 模块,那么你可能已经为代码示例创建了一个项目文件夹。 如果是这种情况,可以跳过下一步,该步骤用于在 TestProject 文件夹中创建控制台应用。

  6. 在终端命令提示符处,若要在指定文件夹中新建控制台应用程序,请键入“dotnet new console -o ./CsharpProjects/TestProject”,然后按 Enter。

    此 .NET CLI 命令使用 .NET 程序模板在指定文件夹位置创建新的 C# 控制台应用程序项目。 该命令会自动创建 CsharpProjects 和 TestProject 文件夹,并使用 TestProject 作为 .csproj 文件的名称。

  7. 在“资源管理器”面板中,展开“CsharpProjects”文件夹。

    你应会看到 TestProject 文件夹和两个文件,一个名为 Program.cs 的 C# 程序文件和一个名为 TestProject.csproj 的 C# 项目文件。

  8. 在“资源管理器”面板中,若要在“编辑器”面板中查看代码文件,请选择“Program.cs”。

  9. 删除现有代码行。

    在本模块中,你将使用此 C# 控制台项目来创建、生成和运行代码示例。

  10. 关闭“终端”面板。

调用 .NET 类库中不同种类的方法

  1. 在 Visual Studio Code 编辑器中,若要创建实现 System.RandomSystem.Console 类的方法的代码示例,请输入以下代码:

    Random dice = new Random();
    int roll = dice.Next(1, 7);
    Console.WriteLine(roll);
    
    

    此代码使用 Random.Next() 方法模拟掷骰子活动来生成数字,使用 Console.WriteLine() 方法显示值。

    注意

    你将在本单元的稍后部分详细查看此代码。

  2. 在 Visual Studio Code 的“文件”菜单上,单击“保存”。

  3. 在“资源管理器”面板中,若要在 TestProject 文件夹位置打开终端,请右键单击“TestProject”,然后选择“在集成终端中打开”。

    请注意,终端面板包含一个显示文件夹路径的命令提示符。 例如:

    C:\Users\someuser\Desktop\CsharpProjects\TestProject>

    使用终端运行 .NET CLI 命令时,此文件夹位置就是命令的运行位置。 在生成或运行代码之前,请确保代码文件夹与命令提示符中显示的文件夹路径匹配。

  4. 在终端命令提示符处,若要运行代码,请键入 dotnet run,然后按 Enter。

    请注意,控制台输出中显示一个介于 1 到 6 之间的数字(骰子上面的点数)。 如果运行代码的次数足够多,最终将看到显示每个数字。

  5. 花点时间检查一下用于访问 Next()WriteLine() 方法的语法。

    请注意,使用不同的技术来访问方法。

    Random dice = new Random();
    int roll = dice.Next(1, 7);
    Console.WriteLine(roll);
    
    

    在第三个代码行中,包括对 Console 类的引用并直接调用 Console.WriteLine() 方法。 不过,使用另一种技术调用 Random.Next() 方法。 使用两种不同的技术进行调用的原因是,有些方法是有状态的,而有些方法是无状态的。 下一步是检查有状态方法和无状态方法之间的差异。

有状态方法与无状态方法

在软件开发项目中,“状态”这个词用于描述执行环境在特定时刻的状态。 代码逐行执行时,值存储在变量中。 在执行过程中的任何时候,应用程序的当前状态为存储在内存中的所有值的集合。

某些方法的正常工作不依赖于应用程序的当前状态。 换言之,实现无状态方法是为了在不引用或更改内存中存储的任何值的情况下正常工作。 无状态方法也称为静态方法

例如,Console.WriteLine() 方法不依赖于内存中存储的任何值。 该方法执行其函数并完成工作,而不会以任何方式影响应用程序的状态。

但是,其他方法必须有权访问应用程序的状态,才能正常工作。 换言之,有状态方法的构建方式使得这些方法依赖于先前已执行的代码行存储在内存中的值。 或者,有状态方法通过更新值或将新值存储在内存中来修改应用程序的状态。 它们也称为实例方法。

有状态(实例)方法在字段中跟踪方法的状态,这些字段是在类上定义的变量。 对于存储状态的这些字段,类的每个新实例都将获取其自己的副本。

单个类可支持有状态方法和无状态方法。 但是,需要调用有状态方法时,必须首先创建类的实例,这样方法才能访问状态。

创建类的实例

类的实例称为对象。 若要创建类的新实例,请使用 new 运算符。 请考虑下面这一代码行,此代码行可创建 Random 类的新实例,以此创建名为 dice 的新对象:

Random dice = new Random();

new 运算符执行以下几项重要操作:

  • 首先请求足够大的计算机内存地址,用于存储基于 Random 类的新对象。
  • 创建新的对象,并将其存储在内存地址上。
  • 返回内存地址,使其保存在 dice 变量中。

从此时起,引用 dice 变量时,.NET 运行时在幕后执行查找操作,这会造成一种直接使用对象本身的假象。

使用最新版本的 .NET 运行时可以实例化对象,而无需重复类型名称(目标类型的构造函数调用)。 例如,以下代码将创建 Random 类的新实例:

Random dice = new();

目的是简化代码可读性。 编写目标类型 new 表达式时,始终使用括号。

为什么 Next() 方法是有状态的?

你可能想知道为什么 Next() 方法以有状态方法实现? .NET 类库设计器无法找出在无需状态的情况下生成随机数字的方法吗? 而且 Next() 方法存储或引用的内容究竟是什么?

这些都是合理的问题。 在较高的级别上,计算机擅长按照特定指令来创建可靠且可重复的结果。 为了创建随机错觉,Next() 方法的开发者决定将日期和时间具体捕获到毫秒的小数部分,并用它来设置一种算法,使其每次都会生成不同数字。 虽然并非完全随机,但可满足大多数应用程序。 在 dice 对象的生存期内捕获和维护的状态是种子值。 后续每次对 Next() 方法的调用都将重新运行该算法,但需确保种子发生更改,这样才不会返回相同的值。

而要使用 Random.Next() 方法,是无需了解其工作原理的。 需要注意的一点是,一些方法需要在调用该方法之前创建类的实例,而其他方法则不需要。

如何确定是否需要先创建类的实例,然后再调用其方法?

要确定方法是有状态的还是无状态的,一种方式是查阅文档。 文档中包含了一些示例,它们说明了方法是必须从对象实例调用,还是直接从类调用。

注意

你可能需要在文档页面上向下滚动,才能找到代码示例。

除了搜索产品文档,你还可以尝试直接从类本身访问方法。 如果能够访问,就表示它是一种无状态方法。 可能出现的最糟糕的情况是遇到编译错误。

尝试直接访问 Random.Next() 方法并查看发生的情况。

  1. 在 Visual Studio Code 编辑器中,输入以下代码行:

    int result = Random.Next();
    
    

    你已经知道 Next() 是有状态方法,而此示例演示了在你尝试不当访问方法时 Visual Studio Code 编辑器的反应。

  2. 请注意,Random.Next 下会显示一条红色波浪线,指示你出现编译错误。

    如果你有兴趣使用的方法是无状态的,则不会显示红色波浪线。

  3. 将鼠标指针悬停在红色波浪线上。

    应该会显示一个弹出窗口,其中包含以下消息:

    (1,14): error CS0120: An object reference is required for the non-static field, method, or property 'Random.Next()'
    
    

    正如在本单元开头的代码中看到的那样,可通过在访问 Next() 方法之前创建 Random 类的实例来修复此错误。 例如:

    Random dice = new Random();
    int roll = dice.Next();
    
    

    在这种情况下,会在没有输入参数的情况下调用 Next() 方法。

回顾

  • 若要调用 .NET 类库中类的方法,请采用 ClassName.MethodName() 格式,其中 . 符号是成员访问运算符,用于访问在类中定义的方法,而 () 符号是方法调用运算符。
  • 调用无状态方法时,无需先创建其类的新实例。
  • 在调用有状态方法时,需要创建类的实例,并访问对象的方法。
  • 使用 new 运算符创建类的新实例。
  • 类的实例称为对象。

知识检查

1.

下面哪一项是创建类实例的正确方法?

2.

开发人员创建了一个名为 coinsRandom 类实例。 他们可使用下面哪一个代码行来调用 Next() 方法?