C#_官方文档_C#快速入门_篇章
文档地址: https://docs.microsoft.com/zh-cn/dotnet/csharp/quick-starts/index
IDE使用: Visual Studio For Mac
选取你的快速入门
可以从下列任一快速入门教程入手:
C# 中的数字
在 C# 中的数字快速入门教程中,将了解计算机如何存储数字,以及如何对不同类型的数字执行运算。 读者将学习四舍五入的基础知识,以及如何使用 C# 执行数学运算。
若要更好地学习本快速入门教程,需要先完成 Hello World 课程。
分支和循环
在分支和循环快速入门教程中,将了解根据变量中存储的值选择不同代码执行路径的基础知识。 读者将学习控制流的基础知识,这是程序决定选择不同操作的基本依据。
若要更好地学习本快速入门教程,需要先完成 Hello World 和 C# 中的数字课程。
字符串内插
字符串内插快速入门教程将介绍如何将值插入字符串。 你将学习如何创建带有嵌入式 C# 表达式的内插字符串,以及如何控制结果字符串中表达式结果的文本外观。
若要更好地学习本快速入门课程,需要先完成 Hello World、C# 中的数字和分支和循环课程。
列表集合
列表集合课程将介绍存储一系列数据的列表集合类型。 读者将学习如何添加和删除项、如何搜索项,以及如何对列表进行排序。 读者将探索各种列表。
若要更好地学习本快速入门教程,需要已完成上面列出的课程。
类简介
只能在计算机上使用自己的本地开发环境和 .NET Core 演练最后一个快速入门教程。 读者将生成控制台应用程序,并了解 C# 语言中面向对象的基本功能的工作原理。
“C# 中的数字”快速入门
本快速入门教程以交互方式介绍了 C# 中的数字类型。 你将编写少量的代码,然后编译并运行这些代码。本快速入门教程包含一系列课程,介绍了 C# 中的数字和数学操作。 这些课程介绍了 C# 语言的基础知识。
若要学习本快速入门教程,必须有开发计算机。 .NET 主题 10 分钟入门介绍了如何在 Mac、PC 或 Linux 上设置本地开发环境。 本地快速入门教程简介不仅简要概述了将用到的命令,还收录了详细信息链接。
探索整数数学运算
创建名为 numbers-quickstart 的目录。
将新建的目录设为当前目录,并运行 dotnet new console -n NumbersInCSharp -o .
。
在常用编辑器中,打开 Program.cs,并将行 Console.Writeline("Hello Beyond!");
替换为以下代码:
int a = 18;
int b = 6;
int c = a + b;
Console.WriteLine(c);
通过在命令窗口中键入 dotnet run
运行此代码。
刚刚看到的是一种基本的整数数学运算。 int
类型表示整数(正整数或负整数)。 使用 +
符号执行加法运算。 其他常见的整数数学运算包括:
-
:减法运算*
:乘法运算/
:除法运算
首先,探索这些不同类型的运算。 在写入 c
值的行之后添加以下行:
c = a - b;
Console.WriteLine(c);
c = a * b;
Console.WriteLine(c);
c = a / b;
Console.WriteLine(c);
通过在命令窗口中键入 dotnet run
运行此代码。
如果愿意,也可以尝试在同一行中执行多个数学运算。 例如,请尝试 c = a + b - 12 * 17;
。 允许混合使用变量和常数。
提示
在探索 C#(或任何编程语言)的过程中,可能会在编写代码时犯错。 编译器会发现并报告这些错误。如果输出中包含错误消息,请仔细比对示例代码和你的窗口中的代码,看看哪些需要纠正。 这样做有助于了解 C# 代码结构。
你已完成第一步。 开始进入下一部分前,先将当前代码移到单独的方法中。 这样一来,可以更轻松地开始处理新示例。 将 Main
方法重命名为 WorkingWithIntegers
,并编写调用 WorkingWithIntegers
的新 Main
方法。 完成后,代码应如下所示:
using System;
namespace NumbersInCSharp
{
class Program
{
static void WorkingWithIntegers()
{
int a = 18;
int b = 6;
int c = a + b;
Console.WriteLine(c);
c = a - b;
Console.WriteLine(c);
c = a * b;
Console.WriteLine(c);
c = a / b;
Console.WriteLine(c);
}
static void Main(string[] args)
{
WorkingWithIntegers();
}
}
}
探索运算顺序
注释掉对 WorkingWithIntegers()
的调用。 在本节中,它会在你工作时使输出变得不那么杂乱:
//WorkingWithIntegers();
//
在 C# 中启动 注释。 注释是你想要保留在源代码中但不能作为代码执行的任何文本。 编译器不会从注释中生成任何可执行代码。
C# 语言使用与数学运算规则一致的规则,定义不同数学运算的优先级。 乘法和除法的优先级高于加法和减法。 将以下代码添加到 Main
方法,然后执行 dotnet run
进行探索:
int a = 5;
int b = 4;
int c = 2;
int d = a + b * c;
Console.WriteLine(d);
输出结果表明,乘法先于加法执行。
可以在要优先执行的一个或多个运算前后添加括号,从而强制改变运算顺序。 添加以下行并再次运行:
d = (a + b) * c;
Console.WriteLine(d);
通过组合多个不同的运算,进一步探索运算顺序。 在 Main
方法底部添加类似以下行的内容。 重试 dotnet run
。
d = (a + b) - 6 * c + (12 * 4) / 3 + 12;
Console.WriteLine(d);
可能已注意到,整数有一个非常有趣的行为。 整数除法始终生成整数结果,即使预期结果有小数或分数部分也是如此。
如果你没有注意到此行为,请在 Main
方法结束时试运行以下代码:
int e = 7;
int f = 4;
int g = 3;
int h = (e + f) / g;
Console.WriteLine(h);
再次键入 dotnet run
,看看结果如何。
继续之前,让我们获取你在本节编写的所有代码并放在新的方法中。 调用新方法 OrderPrecedence
。 最后应以与下面类似的代码结束:
using System;
namespace NumbersInCSharp
{
class Program
{
static void WorkingWithIntegers()
{
int a = 18;
int b = 6;
int c = a + b;
Console.WriteLine(c);
c = a - b;
Console.WriteLine(c);
c = a * b;
Console.WriteLine(c);
c = a / b;
Console.WriteLine(c);
}
static void OrderPrecedence()
{
int a = 5;
int b = 4;
int c = 2;
int d = a + b * c;
Console.WriteLine(d);
d = (a + b) * c;
Console.WriteLine(d);
d = (a + b) - 6 * c + (12 * 4) / 3 + 12;
Console.WriteLine(d);
int e = 7;
int f = 4;
int g = 3;
int h = (e + f) / g;
Console.WriteLine(h);
}
static void Main(string[] args)
{
WorkingWithIntegers();
OrderPrecedence();
}
}
}
探索整数运算精度和限值
在上一个示例中,整数除法截断了结果。 可以使用取模运算符(即 %
字符)计算余数。 在 Main
方法中试用以下代码:
int a = 7;
int b = 4;
int c = 3;
int d = (a + b) / c;
int e = (a + b) % c;
Console.WriteLine($"quotient: {d}");
Console.WriteLine($"remainder: {e}");
C# 整数类型不同于数学上的整数的另一点是,int
类型有最小限值和最大限值。 将此代码添加到 Main
方法,看看这些限制的运行机制:
int max = int.MaxValue;
int min = int.MinValue;
Console.WriteLine($"The range of integers is {min} to {max}");
如果运算生成的值超过这些限值,则会出现下溢或溢出的情况。 答案似乎是从一个限值覆盖到另一个限值的范围。 例如,将以下两行添加到 Main
方法:
int what = max + 3;
Console.WriteLine($"An example of overflow: {what}");
可以看到,答案非常接近最小(负)整数。 与 min + 2
相同。 加法运算会让整数溢出允许的值。 答案是一个非常大的负数,因为溢出从最大整数值覆盖回最小整数值。
如果 int
类型无法满足需求,还会用到限值和精度不同的其他数字类型。 接下来,将探索这些类型。
让我们再一次将你在本节编写的代码移到一个单独的方法中。 将其命名为 TestLimits
。
使用双精度类型
double
数字类型表示双精度浮点数。 这些词可能是第一次听说。 浮点数可用于表示数量级可能非常大或非常小的非整数。 双精度意味着存储这些数字时使用的精度高于单精度。 在新式计算机上,使用双精度数字比使用单精度数字更为常见。 接下来,将探索双精度类型。 添加以下代码并查看结果:
double a = 5;
double b = 4;
double c = 2;
double d = (a + b) / c;
Console.WriteLine(d);
可以看到,答案商包含小数部分。 试试对双精度类型使用更复杂一点的表达式:
double e = 19;
double f = 23;
double g = 8;
double h = (e + f) / g;
Console.WriteLine(h);
双精度值的范围远大于整数值。 在当前已编写的代码下方试运行以下代码:
double max = double.MaxValue;
double min = double.MinValue;
Console.WriteLine($"The range of double is {min} to {max}");
打印出来的这些值用科学记数法表示。 E
左侧为有效数字。 右侧为是 10 的 n 次幂。
与数学上的十进制数字一样,C# 中的双精度值可能会有四舍五入误差。 试运行以下代码:
double third = 1.0 / 3.0;
Console.WriteLine(third);
众所周知,0.3
循环小数与 1/3
并不完全相等。
挑战
尝试使用 double
类型执行其他的大小数、乘法和除法运算。 尝试执行更复杂的运算。
花了一些时间应对挑战之后,获取已编写的代码并放在一个新方法中。 将新方法命名为 WorkWithDoubles
。
使用固定点类型
大家已学习了 C# 中的基本数字类型,即整数和双精度。 下面将介绍另一种需要了解的类型,即 decimal
类型。 decimal
类型的范围较小,但精度高于 double
。 “固定点”一词意味着,十进制小数点(或二进制小数点)不会移动。 让我们来实际操作一下:
decimal min = decimal.MinValue;
decimal max = decimal.MaxValue;
Console.WriteLine($"The range of the decimal type is {min} to {max}");
可以看到,范围小于 double
类型。 通过试运行以下代码,可以看到十进制类型的精度更高:
double a = 1.0;
double b = 3.0;
Console.WriteLine(a / b);
decimal c = 1.0M;
decimal d = 3.0M;
Console.WriteLine(c / d);
数字中的 M
后缀指明了常数应如何使用 decimal
类型。
可以看到,使用十进制类型执行数学运算时,十进制小数点右侧的数字更多。
挑战
至此,大家已了解不同的数字类型。请编写代码来计算圆面积(其中,半径为 2.50 厘米)。 请注意,圆面积是用半径的平方乘以 PI 进行计算。 小提示:.NET 包含 PI 常数 Math.PI,可用于相应的值计算。
你应获得 19 和 20 之间的答案。 要查看你的答案,可以查看 GitHub 上的完成示例代码
如果需要,可以试用一些其他公式。
已完成“C# 中的数字”快速入门教程。 可以在自己的开发环境中继续学习分支和循环快速入门教程。
分支和循环
本快速入门教程介绍了如何编写代码来检查变量,并根据这些变量更改执行路径。 读者可以编写 C# 代码并查看代码编译和运行结果。 本快速入门教程包含一系列课程,介绍了 C# 中的分支和循环构造。 这些课程介绍了 C# 语言的基础知识。
若要学习本快速入门教程,必须有开发计算机。 .NET 主题 10 分钟入门介绍了如何在 Mac、PC 或 Linux 上设置本地开发环境。 本地快速入门教程简介不仅简要概述了将用到的命令,还收录了详细信息链接。
使用 if
语句做出决定
创建名为 branches-quickstart 的目录。 将新建的目录设为当前目录,并运行 dotnet new console -n BranchesAndLoops -o .
。 此命令会在当前目录中创建一个新的 .NET Core 控制台应用程序。
在常用编辑器中,打开 Program.cs,并将行 Console.Writeline("Hello World!");
替换为以下代码:
int a = 5;
int b = 6;
if (a + b > 10)
Console.WriteLine("The answer is greater than 10.");
通过在控制台窗口键入 dotnet run
试运行此代码。 你应在控制台上看到以下消息:“The answer is greater than 10. (答案大于 10)”。
修改 b
的声明,让总和小于 10:
int b = 3;
再次键入 dotnet run
。 由于答案小于 10,因此什么也没有打印出来。 要测试的条件为 false。 没有任何可供执行的代码,因为仅为 if
语句编写了一个可能分支,即 true 分支。
提示
在探索 C#(或任何编程语言)的过程中,可能会在编写代码时犯错。 编译器会发现并报告这些错误。仔细查看错误输出和生成错误的代码。 编译器错误通常可帮助你找出问题。
第一个示例展示了 if
和布尔类型的用途。 布尔变量可以包含下列两个值之一:true
或 false
。 C# 为布尔变量定义了特殊类型 bool
。 if
语句检查 bool
的值。 如果值为 true
,执行 if
后面的语句。否则,跳过上述语句。
这种检查条件并根据条件执行语句的过程非常强大。
让 if 和 else 完美配合
若要执行 true 和 false 分支中的不同代码,请创建在条件为 false 时执行的 else
分支。 试运行这些代码。将以下代码中的最后两行添加到 Main
方法(你应该已经有前四个):
int a = 5;
int b = 3;
if (a + b > 10)
Console.WriteLine("The answer is greater than 10");
else
Console.WriteLine("The answer is not greater than 10");
只有当条件的测试结果为 false
时,才执行 else
关键字后面的语句。 将 if
、else
与布尔条件相结合,可以满足处理 true
和 false
所需的一切要求。
重要
if
和 else
语句下的缩进是为了方便读者阅读。 C# 语言忽略缩进或空格。 if
或 else
关键字后面的语句根据条件决定是否执行。 本快速入门教程中的所有示例都遵循了常见做法,根据语句的控制流缩进代码行。
由于缩进会被忽略,因此需要使用 {
和 }
,指明要在根据条件决定是否执行的代码块中添加多个语句。C# 程序员通常会对所有 if
和 else
子句使用这些大括号。 以下示例与刚刚创建的示例相同。 修改上面的代码以匹配下面的代码:
int a = 5;
int b = 3;
if (a + b > 10)
{
Console.WriteLine("The answer is greater than 10");
}
else
{
Console.WriteLine("The answer is not greater than 10");
}
提示
本快速入门教程其余部分的所有代码示例都遵循了公认做法,添加了大括号。
可以测试更复杂的条件。 在 Main
方法中,在当前已编写的代码之后添加以下代码:
int c = 4;
if ((a + b + c > 10) && (a > b))
{
Console.WriteLine("The answer is greater than 10");
Console.WriteLine("And the first number is greater than the second");
}
else
{
Console.WriteLine("The answer is not greater than 10");
Console.WriteLine("Or the first number is not greater than the second");
}
&&
表示“且”。 也就是说,两个条件必须都为 true,才能执行 true 分支中的语句。 这些示例还表明,可以在每个条件分支中添加多个语句,前提是将它们用 {
和 }
括住。
还可以使用 ||
表示“或”。 在当前已编写的代码之后添加以下代码:
if ((a + b + c > 10) || (a > b))
{
Console.WriteLine("The answer is greater than 10");
Console.WriteLine("Or the first number is greater than the second");
}
else
{
Console.WriteLine("The answer is not greater than 10");
Console.WriteLine("And the first number is not greater than the second");
}
你已完成第一步。 开始进入下一部分前,先将当前代码移到单独的方法中。 这样一来,可以更轻松地开始处理新示例。 将 Main
方法重命名为 ExploreIf
,并编写调用 ExploreIf
的新 Main
方法。 完成后,代码应如下所示:
using System;
namespace BranchesAndLoops
{
class Program
{
static void ExploreIf()
{
int a = 5;
int b = 3;
if (a + b > 10)
{
Console.WriteLine("The answer is greater than 10");
}
else
{
Console.WriteLine("The answer is not greater than 10");
}
if ((a + b + c > 10) && (a > b))
{
Console.WriteLine("The answer is greater than 10");
Console.WriteLine("And the first number is greater than the second");
}
else
{
Console.WriteLine("The answer is not greater than 10");
Console.WriteLine("Or the first number is not greater than the second");
}
if ((a + b + c > 10) || (a > b))
{
Console.WriteLine("The answer is greater than 10");
Console.WriteLine("Or the first number is greater than the second");
}
else
{
Console.WriteLine("The answer is not greater than 10");
Console.WriteLine("And the first number is not greater than the second");
}
}
static void Main(string[] args)
{
ExploreIf();
}
}
}
注释掉对 ExploreIf()
的调用。 在本节中,它会在你工作时使输出变得不那么杂乱:
//ExploreIf();
//
在 C# 中启动 注释。 注释是你想要保留在源代码中但不能作为代码执行的任何文本。 编译器不会从注释中生成任何可执行代码。
使用循环重复执行运算
在本节使用循环以重复执行语句。 请在 Main
方法中试用以下代码:
int counter = 0;
while (counter < 10)
{
Console.WriteLine($"Hello World! The counter is {counter}");
counter++;
}
while
语句会检查条件,并执行 while
后面的语句或语句块。 除非条件为 false,否则它会重复检查条件并执行这些语句。
此示例新引入了另外一个运算符。 counter
变量后面的 ++
是增量运算符。 它将 counter
值加 1,并将计算后的值存储在 counter
变量中。
重要
请确保 while
循环条件在你执行代码时更改为 false。 否则,创建的就是无限循环,即程序永不结束。 本示例中没有演示上述情况,因为你必须使用 CTRL-C 或其他方法强制退出程序。
while
循环先测试条件,然后再执行 while
后面的代码。 do
... while
循环先执行代码,然后再检查条件。 下面的代码对 Do While 循环进行了演示:
counter = 0;
do
{
Console.WriteLine($"Hello World! The counter is {counter}");
counter++;
} while (counter < 10);
此 do
循环和前面的 while
循环生成的输出结果相同。
使用 for 循环
For 循环通常用在 C# 中。 请在 Main() 方法中试用以下代码:
for(int index = 0; index < 10; index++)
{
Console.WriteLine($"Hello World! The index is {index}");
}
此循环的工作原理与已用过的 while
循环和 do
循环相同。 for
语句包含三个控制具体工作方式的部分。
第一部分是 for 初始值设定项:for index = 0;
声明 index
是循环变量,并将它的初始值设置为 0
。
中间部分是 for 条件:index < 10
声明只要计数器值小于 10,此 for
循环就会继续执行。
最后一部分是 for 迭代器:index++
指定在执行 for
语句后面的代码块后,如何修改循环变量。 在此示例中,它指定 index
应在代码块每次执行时递增 1。
亲自试运行这些部分的代码。 试着执行下列两项操作:
- 将初始值设定项更改为其他初始值。
- 将结束条件设定项更改为其他值。
完成后,继续利用所学知识,试着自己编写一些代码。
结合使用分支和循环
支持,大家已了解 C# 语言中的 if
语句和循环构造。看看能否编写 C# 代码,计算 1 到 20 中所有可被 3 整除的整数的总和。 下面提供了一些提示:
%
运算符可用于获取除法运算的余数。if
语句中的条件可用于判断是否应将数字计入总和。for
循环有助于对 1 到 20 中的所有数字重复执行一系列步骤。
亲自试一试吧。 然后,看看自己是怎么做到的。 你应获取的答案为 63。 通过在 GitHub 上查看已完成的代码,你可以看到一个可能的答案。
已完成“分支和循环”快速入门教程。
你可继续在自己的开发环境中学习字符串内插快速入门教程。
字符串内插
本快速入门教程介绍了如何使用 C# 字符串内插将值插入单个结果字符串中。 读者可以编写 C# 代码并查看代码编译和运行结果。 本快速入门教程包含一系列课程,介绍了如何将值插入字符串,以及用不同方式设置这些值的格式。
若要学习本快速入门教程,必须有开发计算机。 .NET 主题 10 分钟入门介绍了如何在 Mac、PC 或 Linux 上设置本地开发环境。 本地快速入门教程简介不仅简要概述了将用到的命令,还收录了详细信息链接。 还可在浏览器中完成本快速入门教程的交互式版本。
创建内插字符串
创建名为 interpolated 的目录。 将其设置为当前目录并从控制台窗口运行以下命令:
dotnet new console
此命令会在当前目录中创建一个新的 .NET Core 控制台应用程序。
在常用编辑器中,打开 Program.cs,将行 Console.WriteLine("Hello World!");
替换为以下代码,并将 <name>
替换为你的姓名 :
var name = "<name>";
Console.WriteLine($"Hello, {name}. It's a pleasure to meet you!");
通过在控制台窗口键入 dotnet run
试运行此代码。 当运行该程序时,它会在问候语中显示一个包含你的姓名的字符串。 WriteLine 方法调用中包含的字符串是一个内插字符串。 这是一种模板,可让你用包含嵌入代码的字符串构造单个字符串(称为结果字符串)。 内插字符串特别适用于将值插入字符串或连接字符串(将字符串联在一起)。
该简单示例包含了每个内插字符串必须具有的两个元素:
-
字符串文本以
$
字符开头,后接左双引号字符。$
符号和引号字符之间不能有空格。 (如果希望看到包含空格会发生什么情况,请在$
字符后面插入一个空格并保存该文件,然后在控制台窗口中键入dotnet run
再次运行该程序。 C# 编译器显示错误消息“错误 CS1056: 意外的字符 '$'”。) -
一个或多个内插表达式。 左大括号和右大括号(
{
和}
)指示内插表达式。 可将任何返回值的 C# 表达式置于大括号内(包括null
)。
下面再尝试一些其他数据类型的字符串内插示例。
包含不同的数据类型
上一节使用了字符串内插将一个字符串插入到了另一字符串中。 不过,内插字符串表达式的结果可以是任何数据类型。 下面让我们在内插字符串中添加多种数据类型的值。
在以下示例中,首先定义一个具有 Name
属性和 ToString
方法的类数据类型 Vegetable
,它可以替代Object.ToString() 方法的行为。 public
访问修饰符使该方法可用于任何客户端代码以获取 Vegetable
实例的字符串表示形式。 在本示例中,Vegetable.ToString
方法返回在 Vegetable
构造函数处初始化的 Name
属性的值:
public Vegetable(string name) => Name = name;
然后,通过使用 new
关键字并为构造函数 Vegetable
提供一个名称参数来创建 Vegetable
类的实例:
var item = new Vegetable("eggplant");
最后,将 item
变量添加到同样包含 DateTime 值、Decimal 值和 Unit
枚举值的内插字符串中。 将编辑器中的所有 C# 代码替换为以下代码,然后使用 dotnet run
命令运行:
using System;
public class Vegetable
{
public Vegetable(string name) => Name = name;
public string Name { get; }
public override string ToString() => Name;
}
public class Program
{
public enum Unit { item, pound, ounce, dozen };
public static void Main()
{
var item = new Vegetable("eggplant");
var date = DateTime.Now;
var price = 1.99m;
var unit = Unit.item;
Console.WriteLine($"On {date}, the price of {item} was {price} per {unit}.");
}
}
注意,内插字符串中的内插表达式 item
会解析为结果字符串中的“eggplant”文本。 这是因为,当表达式结果的类型不是字符串时,会按照以下方式将其解析为字符串:
-
如果内插表达式的计算结果为
null
,则会使用一个空字符串("" 或 String.Empty)。 -
如果内插表达式的计算结果不是
null
,通常会调用结果类型的ToString
方法。 可以通过更新Vegetable.ToString
方法的实现来进行测试。 你甚至不用实现ToString
方法,因为每个类型都有一些此方法的实现。 可通过注释掉示例中Vegetable.ToString
方法的定义(在它前面添加注释符号//
即可)来进行测试。 在输出中,字符串“eggplant”被替换为完全限定的类型名称(本示例中为“Vegetable”),这是 Object.ToString() 方法的默认行为。 对于枚举值的ToString
方法,其默认行为是返回该值的字符串表示形式。
在此示例的输出中,日期过于精确(eggplant 的价格不会以秒为单位变化),且价格值没有标明货币单位。 下一节将介绍如何通过控制表达式结果的字符串表示形式来解决这些问题。
控制内插表达式的格式
上一节将两个格式不正确的字符串插入到了结果字符串中。 一个是日期和时间值,只有日期是合适的。 第二个是没有标明货币单位的价格。 这两个问题都很容易解决。 通过字符串内插,可以指定用于控制特定类型格式的格式字符串。 将前面示例中的调用修改为 Console.WriteLine
,从而包含日期和价格表达式的格式字符串,如以下行所示:
Console.WriteLine($"On {date:d}, the price of {item} was {price:C2} per {unit}.");
可通过在内插表达式后接冒号(“:”)和格式字符串来指定格式字符串。 “d”是标准日期和时间格式字符串,表示短日期格式。 “C2”是标准数值格式字符串,用数字表示货币值(精确到小数点后两位)。
.NET 库中的许多类型支持一组预定义的格式字符串。 这些格式字符串包括所有数值类型以及日期和时间类型。 有关支持格式字符串的完整类型列表,请参阅 .NET 中的格式化类型文章中的格式字符串和. NET 类库类型。
尝试在文本编辑器中修改格式字符串,并在每次更改时重新运行该程序,查看更改如何影响日期和时间以及数值的格式。 将 {date:d}
中的“d”更改为“t”(显示短时间格式)、“y”(显示年份和月份)和“yyyy”(显示四位数年份)。 将 {price:C2}
中的“C2”更改为“e”(用于指数计数法)和“F3”(使数值在小数点后保持三位数字)。
除了控制格式之外,还可以控制结果字符串中包含的格式字符串的字段宽度和对齐方式。 下一节会介绍如何执行此操作。
控制内插表达式的字段宽度和对齐方式
通常,当内插表达式的结果格式化为字符串时,结果字符串中会包含该字符串,但没有前导或尾随空格。特别是对于使用一组数据的情况,控制字段宽度和对齐方式有助于增强输出的可读性。 为此,用下方代码替换文本编辑器中的所有代码,然后键入 dotnet run
来执行程序:
using System;
using System.Collections.Generic;
public class Example
{
public static void Main()
{
var titles = new Dictionary<string, string>()
{
["Doyle, Arthur Conan"] = "Hound of the Baskervilles, The",
["London, Jack"] = "Call of the Wild, The",
["Shakespeare, William"] = "Tempest, The"
};
Console.WriteLine("Author and Title List");
Console.WriteLine();
Console.WriteLine($"|{"Author",-25}|{"Title",30}|");
foreach (var title in titles)
Console.WriteLine($"|{title.Key,-25}|{title.Value,30}|");
}
}
创建者姓名采用左对齐方式,其所写标题采用右对齐方式。 通过在内插表达式后面添加一个逗号(“,”)并指定“最小”字段宽度来指定对齐方式。 如果指定的值是正数,则该字段为右对齐。 如果它为负数,则该字段为左对齐。
尝试删除 {"Author",-25}
和 {title.Key,-25}
代码中的负号,然后再次运行该示例,如以下代码所示:
Console.WriteLine($"|{"Author",25}|{"Title",30}|");
foreach (var title in titles)
Console.WriteLine($"|{title.Key,25}|{title.Value,30}|");
此时,创建者信息为右对齐。
可合并单个内插表达式中的对齐说明符和格式字符串。 为此,请先指定对齐方式,然后是冒号和格式字符串。 将 Main
方法中的所有代码替换为以下代码,该代码用定义的字段宽度显示格式化字符串。 然后输入 dotnet run
命令来运行程序。
Console.WriteLine($"[{DateTime.Now,-20:d}] Hour [{DateTime.Now,-10:HH}] [{1063.342,15:N2}] feet");
输出类似于以下内容:
[04/14/2018 ] Hour [16 ] [ 1,063.34] feet
已完成“字符串内插”快速入门教程。
你可继续在自己的开发环境中学习列表集合快速入门教程。
C# 快速入门:集合
本快速入门教程介绍了 C# 语言和 List<T> 类的基础知识。
若要学习本快速入门教程,必须有开发计算机。 .NET 主题 10 分钟入门介绍了如何在 Mac、PC 或 Linux 上设置本地开发环境。 本地快速入门教程简介不仅简要概述了将用到的命令,还收录了详细信息链接。
基本列表示例
创建名为 list-quickstart 的目录。 将新建的目录设为当前目录,并运行 dotnet new console
。
备注
如果你刚完成 10 分钟 .NET 入门,则可以继续使用刚刚创建的 myApp 应用程序。
在常用编辑器中,打开 Program.cs,并将现有代码替换为以下代码:
using System;
using System.Collections.Generic;
namespace list_quickstart
{
class Program
{
static void Main(string[] args)
{
var names = new List<string> { "<name>", "Ana", "Felipe" };
foreach (var name in names)
{
Console.WriteLine($"Hello {name.ToUpper()}!");
}
}
}
}
将 <name>
替换为自己的名称。 保存 Program.cs。 在控制台窗口中键入 dotnet run
,试运行看看。
刚刚创建了一个字符串列表,并向其中添加了三个名称,再输出了全部大写的名称。 循环访问整个列表需要用到,在前面的快速入门课程中学到的概念。
用于显示名称的代码使用字符串内插功能。 如果 string
前面有 $
符号,可以在字符串声明中嵌入 C# 代码。 实际字符串使用自己生成的值替换该 C# 代码。 在此示例中,{name.ToUpper()}
被替换为各个转换为大写字母的名称,因为调用了 ToUpper 方法。
接下来将进一步探索。
修改列表内容
创建的集合使用 List<T> 类型。 此类型存储一系列元素。 元素类型是在尖括号内指定。
List<T> 类型的一个重要方面是,既可以扩大,也可以收缩,方便用户添加或删除元素。 在 Main
方法的右 }
前添加以下代码:
C#复制
Console.WriteLine();
names.Add("Maria");
names.Add("Bill");
names.Remove("Ana");
foreach (var name in names)
{
Console.WriteLine($"Hello {name.ToUpper()}!");
}
又向列表的末尾添加了两个名称。 同时,也删除了一个名称。 保存此文件,并键入 dotnet run
,试运行看看。
借助 List<T>,还可以按索引引用各项。 索引位于列表名称后面的 [
和 ]
令牌之间。 C# 对第一个索引使用 0。 将以下代码添加到刚才添加的代码的正下方,并试运行看看:
Console.WriteLine($"My name is {names[0]}");
Console.WriteLine($"I've added {names[2]} and {names[3]} to the list");
不得访问超出列表末尾的索引。 请注意,索引是从 0 开始编制,因此最大有效索引是用列表项数减 1 计算得出。 可以使用 Count 属性确定列表长度。 在 Main 方法的末尾,添加以下代码:
Console.WriteLine($"The list has {names.Count} people in it");
保存此文件,并再次键入 dotnet run
看看结果如何。
搜索列表并进行排序
我们的示例使用的列表较小,但大家的应用程序创建的列表通常可能会包含更多元素,有时可能会包含数以千计的元素。 若要在更大的集合中查找元素,需要在列表中搜索不同的项。 IndexOf 方法可搜索项,并返回此项的索引。 将以下代码添加到 Main
方法的底部:
var index = names.IndexOf("Felipe");
if (index == -1)
{
Console.WriteLine($"When an item is not found, IndexOf returns {index}");
} else
{
Console.WriteLine($"The name {names[index]} is at index {index}");
}
index = names.IndexOf("Not Found");
if (index == -1)
{
Console.WriteLine($"When an item is not found, IndexOf returns {index}");
} else
{
Console.WriteLine($"The name {names[index]} is at index {index}");
}
还可以对列表中的项进行排序。 Sort 方法按正常顺序(按字母顺序,如果是字符串的话)对列表中的所有项进行排序。 将以下代码添加到 Main
方法的底部:
names.Sort();
foreach (var name in names)
{
Console.WriteLine($"Hello {name.ToUpper()}!");
}
保存此文件,并键入 dotnet run
,试运行此最新版程序。
开始进入下一部分前,先将当前代码移到单独的方法中。 这样一来,可以更轻松地开始处理新示例。 将 Main
方法重命名为 WorkingWithStrings
,并编写调用 WorkingWithStrings
的新 Main
方法。 完成后,代码应如下所示:
using System;
using System.Collections.Generic;
namespace list_quickstart
{
class Program
{
static void Main(string[] args)
{
WorkingWithStrings();
}
public static void WorkingWithStrings()
{
var names = new List<string> { "<name>", "Ana", "Felipe" };
foreach (var name in names)
{
Console.WriteLine($"Hello {name.ToUpper()}!");
}
Console.WriteLine();
names.Add("Maria");
names.Add("Bill");
names.Remove("Ana");
foreach (var name in names)
{
Console.WriteLine($"Hello {name.ToUpper()}!");
}
Console.WriteLine($"My name is {names[0]}");
Console.WriteLine($"I've added {names[2]} and {names[3]} to the list");
Console.WriteLine($"The list has {names.Count} people in it");
var index = names.IndexOf("Felipe");
Console.WriteLine($"The name {names[index]} is at index {index}");
var notFound = names.IndexOf("Not Found");
Console.WriteLine($"When an item is not found, IndexOf returns {notFound}");
names.Sort();
foreach (var name in names)
{
Console.WriteLine($"Hello {name.ToUpper()}!");
}
}
}
}
其他类型的列表
到目前为止,大家一直在列表中使用 string
类型。 接下来,将让 List<T> 使用其他类型。 那就生成一组数字吧。
将以下代码添加到新 Main
方法的底部:
var fibonacciNumbers = new List<int> {1, 1};
这会创建一个整数列表,并将头两个整数设置为值 1。 这些是斐波那契数列(一系列数字)的头两个值。斐波那契数列中的每个数字都是前两个数字之和。 添加以下代码:
var previous = fibonacciNumbers[fibonacciNumbers.Count - 1];
var previous2 = fibonacciNumbers[fibonacciNumbers.Count - 2];
fibonacciNumbers.Add(previous + previous2);
foreach(var item in fibonacciNumbers)
Console.WriteLine(item);
保存此文件,并键入 dotnet run
看看结果如何。
提示
为了能够集中精力探究此部分,可以注释掉调用 WorkingWithStrings();
的代码。 只需在此调用前添加两个 /
字符即可,如 // WorkingWithStrings();
。
挑战
看看能不能将本课程中的一些概念与前面的课程融会贯通。 使用斐波那契数列,扩展当前生成的程序。 试着编写代码,生成此序列中的前 20 个数字。 (作为提示,第 20 个斐波纳契数是 6765。)
完成挑战
可以查看 GitHub 上的完成示例代码,了解示例解决方案
在循环的每次迭代中,取此列表中的最后两个整数进行求和,并将计算出的总和值添加到列表中。 循环会一直重复运行到列表中有 20 个项为止。
恭喜!已完成列表快速入门教程。 可以在自己的开发环境中继续学习类简介快速入门教程。
若要详细了解如何使用 List
类型,可以参阅有关集合的 .NET 指南主题。 还可以了解其他许多集合类型。
类简介
若要学习本快速入门教程,必须有开发计算机。 .NET 主题 10 分钟入门介绍了如何在 Mac、PC 或 Linux 上设置本地开发环境。 本地快速入门教程简介不仅简要概述了将用到的命令,还收录了详细信息链接。
创建应用程序
使用终端窗口,创建名为 classes 的目录。 可以在其中生成应用程序。 将此目录更改为当前目录,并在控制台窗口中键入 dotnet new console
。 此命令可创建应用程序。 打开 Program.cs。 应如下所示:
using System;
namespace classes
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
在本快速入门教程中,将要新建表示银行帐户的类型。 通常情况下,开发者都会在不同的文本文件中定义每个类。 这样可以更轻松地管理不断增大的程序。 在 classes 目录中,新建名为 BankAccount.cs 的文件。
此文件包含“银行帐户”定义。 面向对象的编程组织代码的方式为,创建类形式的类型。 这些类包含表示特定实体的代码。 BankAccount
类表示银行帐户。 代码通过方法和属性实现特定操作。 在本快速入门教程中,银行帐户支持以下行为:
- 用一个 10 位数唯一标识银行帐户。
- 用字符串存储一个或多个所有者名称。
- 可以检索余额。
- 接受存款。
- 接受取款。
- 初始余额必须是正数。
- 取款后的余额不能是负数。
定义银行帐户类型
首先,创建定义此行为的类的基本设置。 具体如下所示:
using System;
namespace classes
{
public class BankAccount
{
public string Number { get; }
public string Owner { get; set; }
public decimal Balance { get; }
public void MakeDeposit(decimal amount, DateTime date, string note)
{
}
public void MakeWithdrawal(decimal amount, DateTime date, string note)
{
}
}
}
继续操作前,先来看看已经生成的内容。 借助 namespace
声明,可以按逻辑组织代码。 由于本快速入门教程的篇幅较小,因此所有代码都将被添加到一个命名空间中。
public class BankAccount
定义要创建的类或类型。 类声明后面 {
和 }
中的所有内容定义了类行为。 BankAccount
类有五个成员。 前三个成员是属性。 属性是数据元素,可以包含强制执行验证或其他规则的代码。 最后两个成员是方法。 方法是执行一个函数的代码块。 读取每个成员的名称应该能够为自己或其他开发者提供了解类用途的足够信息。
打开新帐户
要实现的第一个功能是打开银行帐户。 打开帐户时,客户必须提供初始余额,以及此帐户的一个或多个所有者的相关信息。
新建 BankAccount
类型的对象意味着,定义可分配这些值的构造函数。 构造函数是与类同名的成员。 用于初始化相应类类型的对象。 将以下构造函数添加到 BankAccount
类型中:
public BankAccount(string name, decimal initialBalance)
{
this.Owner = name;
this.Balance = initialBalance;
}
构造函数是在使用 new
创建对象时进行调用。 将 program.cs 中的代码行 Console.WriteLine("Hello World!");
替换为以下代码行(将 <name>
替换为自己的名称):
var account = new BankAccount("<name>", 1000);
Console.WriteLine($"Account {account.Number} was created for {account.Owner} with {account.Balance} initial balance.");
键入 dotnet run
,看看会发生什么。
有没有注意到帐号为空? 是时候解决这个问题了。 帐号应在构造对象时分配。 但不得由调用方负责创建。BankAccount
类代码应了解如何分配新帐号。 这样做的简单方法是从一个 10 位数开始。 帐号随每个新建的帐户而递增。 最后,在构造对象时,存储当前的帐号。
将以下成员声明添加到 BankAccount
类中:
private static int accountNumberSeed = 1234567890;
此为数据成员。 它是 private
,这意味着只能通过 BankAccount
类中的代码访问它。 这是一种分离公共责任(如拥有帐号)与私有实现(如何生成帐号)的方法。将下面两行代码添加到构造函数,以分配帐号:
this.Number = accountNumberSeed.ToString();
accountNumberSeed++;
键入 dotnet run
看看结果如何。
创建存款和取款
银行帐户类必须接受存款和取款,才能正常运行。 接下来,将为银行帐户创建每笔交易日记,实现存款和取款。 与仅更新每笔交易余额相比,这样做有一些优点。 历史记录可用于审核所有交易,并管理每日余额。 通过在需要时根据所有交易的历史记录计算余额,单笔交易中修正的任何错误将会在下次计算余额时得到正确体现。
接下来,先新建表示交易的类型。 这是一个没有任何责任的简单类型。 但需要有多个属性。 新建名为 Transaction.cs 的文件。 向新文件添加以下代码:
using System;
namespace classes
{
public class Transaction
{
public decimal Amount { get; }
public DateTime Date { get; }
public string Notes { get; }
public Transaction(decimal amount, DateTime date, string note)
{
this.Amount = amount;
this.Date = date;
this.Notes = note;
}
}
}
现在,将 Transaction
对象的 List<T> 添加到 BankAccount
类中。 添加以下声明:
private List<Transaction> allTransactions = new List<Transaction>();
List<T> 类要求导入不同的命名空间。 在 BankAccount.cs 的开头,添加以下代码:
using System.Collections.Generic;
现在,更改 Balance
的报告方式。 可以通过对所有交易的值进行求和计算余额。 将 BankAccount
类中 Balance
的声明修改为如下所示:
public decimal Balance
{
get
{
decimal balance = 0;
foreach (var item in allTransactions)
{
balance += item.Amount;
}
return balance;
}
}
此示例反映了属性的一个重要方面。 现在,可以在其他程序员要求获取余额时计算值。 计算会枚举所有交易,总和即为当前余额。
接下来,实现 MakeDeposit
和 MakeWithdrawal
方法。 这些方法将强制执行最后两条规则:初始余额必须为正数,且取款后的余额不能是负数。
这就引入了异常的概念。 指明方法无法成功完成工作的标准方法是抛出异常。 异常类型及其关联消息描述了错误。 在此示例中,如果存款金额为负数,MakeDeposit
方法会抛出异常。 如果取款金额为负数,或取款后的余额为负数,MakeWithdrawal
方法会抛出异常:
public void MakeDeposit(decimal amount, DateTime date, string note)
{
if (amount <= 0)
{
throw new ArgumentOutOfRangeException(nameof(amount), "Amount of deposit must be positive");
}
var deposit = new Transaction(amount, date, note);
allTransactions.Add(deposit);
}
public void MakeWithdrawal(decimal amount, DateTime date, string note)
{
if (amount <= 0)
{
throw new ArgumentOutOfRangeException(nameof(amount), "Amount of withdrawal must be positive");
}
if (Balance - amount < 0)
{
throw new InvalidOperationException("Not sufficient funds for this withdrawal");
}
var withdrawal = new Transaction(-amount, date, note);
allTransactions.Add(withdrawal);
}
throw
语句将引发异常。 当前方法执行结束,并将在找到匹配的 catch
块时继续执行。 添加 catch
块可以稍后再测试一下此代码。
构造函数应进行一处更改,更改为添加初始交易,而不是直接更新余额。 由于已编写 MakeDeposit
方法,因此通过构造函数调用它。 完成的构造函数应如下所示:
public BankAccount(string name, decimal initialBalance)
{
this.Number = accountNumberSeed.ToString();
accountNumberSeed++;
this.Owner = name;
MakeDeposit(initialBalance, DateTime.Now, "Initial balance");
}
DateTime.Now 是返回当前日期和时间的属性。 在 Main
方法中添加几个存款和取款,对此进行测试:
account.MakeWithdrawal(500, DateTime.Now, "Rent payment");
Console.WriteLine(account.Balance);
account.MakeDeposit(100, DateTime.Now, "friend paid me back");
Console.WriteLine(account.Balance);
接下来,尝试创建初始余额为负数的帐户,测试能否捕获到错误条件:
// Test that the initial balances must be positive:
try
{
var invalidAccount = new BankAccount("invalid", -55);
}
catch (ArgumentOutOfRangeException e)
{
Console.WriteLine("Exception caught creating account with negative balance");
Console.WriteLine(e.ToString());
}
使用 try
和 catch
语句,标记可能会抛出异常的代码块,并捕获预期错误。 可以使用相同的技术,测试代码能否在取款后的余额为负数时抛出异常:
// Test for a negative balance
try
{
account.MakeWithdrawal(750, DateTime.Now, "Attempt to overdraw");
}
catch (InvalidOperationException e)
{
Console.WriteLine("Exception caught trying to overdraw");
Console.WriteLine(e.ToString());
}
保存此文件,并键入 dotnet run
,试运行看看。
挑战 - 记录所有交易
为了完成本快速入门教程,可以编写 GetAccountHistory
方法,为交易历史记录创建 string
。 将此方法添加到 BankAccount
类型中:
public string GetAccountHistory()
{
var report = new System.Text.StringBuilder();
report.AppendLine("Date\t\tAmount\tNote");
foreach (var item in allTransactions)
{
report.AppendLine($"{item.Date.ToShortDateString()}\t{item.Amount}\t{item.Notes}");
}
return report.ToString();
}
上面的代码使用 StringBuilder 类,设置包含每个交易行的字符串的格式。 在前面的快速入门教程中,也遇到过字符串格式设置代码。 新增的一个字符为 \t
。 这用于插入选项卡,从而设置输出格式。
添加以下代码行,在 Program.cs 中对它进行测试:
Console.WriteLine(account.GetAccountHistory());
键入 dotnet run
看看结果如何。
后续步骤
如果遇到问题,可以在 GitHub 存储库中查看本快速入门教程的源代码
恭喜!已完成所有快速入门课程。 若要了解详细信息,请学习我们的教程
Github地址:
代码汇总_1:
using System;
using System.Collections.Generic;
namespace cs_09
{
class MainClass
{
public static void Main(string[] args)
{
if(0 == 1){
arithmeticFunction5();
}
if (1 == 2){
int max = int.MaxValue;
int min = int.MinValue;
// -2147483648 to 2147483647
Console.WriteLine($"from {min} to {max}");
}
if (2 == 3){
int max = int.MaxValue;
int min = int.MinValue;
// -2147483648 to 2147483647
Console.WriteLine($"from {min} to {max}");
Console.WriteLine($"{max} + 1 is {max + 1}");
}
if (3 == 4){
double a = 7;
double b = 6;
double c = 5;
double d = (a + b) / c;
Console.WriteLine(d);
}
if (4 == 5){
double a = 5;
double b = 5;
double c = 3;
double d = (a + b) / c;
// 14 位小数
// 1.71428571428571
// 3.33333333333333
Console.WriteLine(d);
}
if (5 == 6){
double min = double.MinValue;
double max = double.MaxValue;
// 1.79769313486232E+308
Console.WriteLine($"from {min} to {max}");
}
if (6 == 7){
double result = 1.0/3.0;
// 15 位小数
// 0.333333333333333
Console.WriteLine(result);
}
if (7 == 8){
decimal min = decimal.MinValue;
decimal max = decimal.MaxValue;
// -79228162514264337593543950335
// 79228162514264337593543950335
Console.WriteLine($"from {min} to {max}");
}
if (8 == 9){
double a = 1.0;
double b = 3.0;
// 15 位小数
// 0.333333333333333
Console.WriteLine(a/b);
decimal d = 1.0M;
decimal e = 3.0M;
// 28 位小数
// 0.3333333333333333333333333333
Console.WriteLine(d / e);
}
if (9 == 10){
int a = 6;
int b = 7;
if(a + b > 10){
Console.WriteLine("Greater than 10");
}
}
if (10 == 11){
int a = 6;
int b = 3;
if (a + b > 10){
Console.WriteLine("Greater than 10");
}else{
Console.WriteLine("Not Greater than 10");
}
}
if (11 == 12)
{
int a = 6;
int b = 7;
int c = 5;
if ((a + b + c) > 10 && (a > b))
{
Console.WriteLine("Greater than 10");
Console.WriteLine("a Greater than b");
}
else
{
Console.WriteLine("Not Greater than 10");
Console.WriteLine("or a Not Greater than b");
}
}
if (12 == 13)
{
int a = 5;
int b = 6;
int c = 7;
if ((a + b + c) > 10 || (a > b))
{
Console.WriteLine("Greater than 10");
Console.WriteLine("or a Greater than b");
}
else
{
Console.WriteLine("Not Greater than 10");
Console.WriteLine("And a Not Greater than b");
}
}
if (13 == 14)
{
int counter = 0;
while(counter < 10){
Console.WriteLine($"{counter}");
counter++;
}
}
if (14 == 15)
{
int counter = 0;
do
{
Console.WriteLine($"{counter}");
counter++;
} while (counter < 10);
}
if (15 == 16)
{
for (int index = 0; index < 10; index++){
Console.WriteLine($"{index}");
}
}
if (16 == 17)
{
var name = "Beyond";
Console.WriteLine($"Hello {name}, I wanna play a game~");
}
if (17 == 18)
{
var item = new Vegetable("eggplant");
var date = DateTime.Now;
var price = 1.99m;
var unit = Unit.item;
// On 2018/7/31 17:57:33, the prise of eggplant was 1.99 per item.
Console.WriteLine($"On {date}, the prise of {item} was {price} per {unit}.");
}
if (18 == 19)
{
var item = new Vegetable("eggplant");
var date = DateTime.Now;
var price = 1.99m;
var unit = Unit.item;
// On 2018/7/31 17:57:33, the prise of eggplant was 1.99 per item.
Console.WriteLine($"On {date}, the prise of {item} was {price} per {unit}.");
}
if (19 == 20)
{
var item = new Vegetable("eggplant");
var date = DateTime.Now;
var price = 1.99m;
var unit = Unit.item;
// Niubility
// On 2018 / 7 / 31, the prise of eggplant was ¥1.99 per item.
// d: 表示日期, t: 表示时间, C2: 表示两位小数
/*
* 将 {date:d} 中的“d”更改为“t”(显示短时间格式)、“y”(显示年份和月份)和“yyyy”(显示四位数年份)。
* 将 {price:C2} 中的“C2”更改为“e”(用于指数计数法)和“F3”(使数值在小数点后保持三位数字)。
*/
Console.WriteLine($"On {date:d}, the prise of {item} was {price:C2} per {unit}.");
}
if(20 == 21){
/*
* Author and Title List
|Author | Title|
|Doyle, Arthur Conan |Hound of the Baskervilles, The|
|London, Jack | Call of the Wild, The|
|Shakespeare, William | Tempest, The|
Press any key to continue...
*/
var titleDict = new Dictionary<string, string>()
{
["Doyle, Arthur Conan"] = "Hound of the Baskervilles, The",
["London, Jack"] = "Call of the Wild, The",
["Shakespeare, William"] = "Tempest, The"
};
Console.WriteLine("Author and Title List");
Console.WriteLine();
Console.WriteLine($"|{"Author",-25}|{"Title",30}|");
foreach(var obj in titleDict){
Console.WriteLine($"|{obj.Key,-25}|{obj.Value,30}|");
}
}
if(21 == 22){
// 同时指定: 对齐说明符和格式字符串
// [2018/8/1 ] Hour [09 ] [ 1,063.34] feet
Console.WriteLine($"[{DateTime.Now,-20:d}] Hour [{DateTime.Now,-10:HH}] [{1063.342,15:N2}] feet");
}
if (22 == 23)
{
var nameArr = new List<string> {"Beyond", "Mathildar", "Menma"};
foreach(var item in nameArr){
Console.WriteLine($"Hello {item.ToUpper()}");
}
}
if (23 == 24)
{
var nameArr = new List<string> {"Beyond", "Mathildar", "Menma"};
// print
foreach (var item in nameArr)
{
Console.WriteLine($"Hello {item.ToUpper()}");
}
// add and remove
Console.WriteLine();
nameArr.Add("Lolita");
nameArr.Remove("Mathildar");
foreach(var item in nameArr){
Console.WriteLine($"Hello {item.ToUpper()}");
}
Console.WriteLine($"My name is {nameArr[0]}, I Love {nameArr[1]} and {nameArr[2]}");
// search
Console.WriteLine();
var index = nameArr.IndexOf("Menma");
if(index == -1){
Console.WriteLine($"Not Found is {index}");
}else{
Console.WriteLine($"{nameArr[index]}'s index is : {index}");
}
// sort
Console.WriteLine();
nameArr.Sort();
foreach(var item in nameArr){
Console.WriteLine($"Hello {item.ToUpper()}");
}
}
if(24 == 25){
// 斐波那契数列 (a3 = a2 + a1)
var fibonacciNumberArr = new List<int> { 1, 1 };
var previous = fibonacciNumberArr[fibonacciNumberArr.Count - 1];
var previous2 = fibonacciNumberArr[fibonacciNumberArr.Count - 2];
fibonacciNumberArr.Add(previous + previous2);
foreach(var item in fibonacciNumberArr){
Console.WriteLine(item);
}
}
if(25 == 26){
// 斐波那契数列 (a3 = a2 + a1)
var fibonacciNumberArr = new List<int> { 1, 1 };
var count = 1;
while(count++ < 19){
var previous = fibonacciNumberArr[fibonacciNumberArr.Count - 1];
var previous2 = fibonacciNumberArr[fibonacciNumberArr.Count - 2];
fibonacciNumberArr.Add(previous + previous2);
}
foreach (var item in fibonacciNumberArr)
{
Console.WriteLine(item);
}
}
if(26 == 27){
var account = new BankAccount("Beyond", 1000);
Console.WriteLine($"Account {account.Number} was created for {account.Owner} with {account.Balance} initial balance. ");
}
if (28 == 28)
{
var account = new BankAccount("Beyond", 1000);
Console.WriteLine($"Account {account.Number} was created for {account.Owner} with {account.Balance} initial balance. ");
account.MakeWithdrawal(500, DateTime.Now, "Rent payment");
Console.WriteLine(account.Balance);
account.MakeDeposit(300, DateTime.Now, "ad fee");
Console.WriteLine(account.Balance);
Console.WriteLine();
Console.WriteLine(account.GetAccountHistory());
}
if (28 == 29)
{
try{
var account = new BankAccount("Beyond", -1000);
}catch(ArgumentOutOfRangeException e){
Console.WriteLine($"Exception : {e.Message}");
Console.WriteLine(e.ToString());
}
}
if (29 == 30)
{
try
{
var account = new BankAccount("Beyond", 1000);
account.MakeWithdrawal(2000, DateTime.Now, "attempt to overdraw");
}
catch (InvalidOperationException e)
{
Console.WriteLine($"Exception : {e.Message}");
Console.WriteLine(e.ToString());
}
}
if (30 == 30)
{
}
}
// ======= other static function =======
static void arithmeticFunction(){
int a = 6;
int b = 7;
int c = a + b;
Console.WriteLine(c);
c = a - b;
Console.WriteLine(c);
c = a * b;
Console.WriteLine(c);
c = a / b;
Console.WriteLine(c);
}
static void arithmeticFunction2()
{
int a = 5;
int b = 6;
int c = 7;
int d = (a + b) * c;
Console.WriteLine(d);
}
static void arithmeticFunction3()
{
int a = 5;
int b = 6;
int c = 7;
int d = (a + b) - 6 * c + (12 * 4) / 3 + 12;
Console.WriteLine(d);
}
static void arithmeticFunction4()
{
int a = 7;
int b = 6;
int c = 5;
int d = (a + b) / c;
Console.WriteLine(d);
}
static void arithmeticFunction5()
{
int a = 7;
int b = 6;
int c = 5;
int d = (a + b) / c;
int e = (a + b) % c;
Console.WriteLine($"quotient: {d}");
Console.WriteLine($"remainder: {e}");
}
// ========== other enum ===========
public enum Unit
{
item,
pound,
ounce,
dozen
};
}
// ========== other class ===========
class Vegetable{
// 定义属性
public string Name { get; }
// constructor
// setter
public Vegetable(string name) =>
this.Name = name;
// return this.Name
public override string ToString() => this.Name;
}
class BankAccount{
// 所有交易
private List<Transaction> allTransactions = new List<Transaction>();
private static int accountNumberSeed = 1234567890;
public string Number{ get; }
public string Owner { get; }
public decimal Balance {
get{
decimal tmpBalance = 0;
foreach(var item in allTransactions){
tmpBalance += item.Amount;
}
return tmpBalance;
}
}
// constructor
public BankAccount(string ownerName, decimal initialBalance)
{
this.Number = accountNumberSeed.ToString();
accountNumberSeed++;
this.Owner = ownerName;
MakeDeposit(initialBalance, DateTime.Now, "Initial Balance");
}
// n. deposit
public void MakeDeposit(decimal amount, DateTime date, string note){
if(amount <= 0){
throw new ArgumentOutOfRangeException(nameof(amount),
"Amount of deposit must be positive");
}
var depositTransaction = new Transaction(amount, date, note);
allTransactions.Add(depositTransaction);
}
// n. withdrawal
public void MakeWithdrawal(decimal amount, DateTime date, string note){
if(amount <= 0){
throw new ArgumentOutOfRangeException(nameof(amount),
"Amount of withdrawal must be positive");
}
if(Balance - amount < 0){
throw new InvalidOperationException("funds not sufficient");
}
var withdrawalTransaction = new Transaction(-amount, date, note);
allTransactions.Add(withdrawalTransaction);
}
// history
public string GetAccountHistory(){
var reportStringBuilder = new System.Text.StringBuilder();
reportStringBuilder.AppendLine("Date\t\tAmount\t\tNote");
foreach(var item in allTransactions){
reportStringBuilder.AppendLine($"{item.Date.ToShortDateString()}\t{item.Amount}\t{item.Notes}");
}
return reportStringBuilder.ToString();
}
}
class Transaction{
public decimal Amount { get; }
public DateTime Date { get; }
public string Notes { get; }
public Transaction(decimal amount, DateTime date, string note){
this.Amount = amount;
this.Date = date;
this.Notes = note;
}
}
}
未完待续,下一章节,つづく