C#学习笔记(docs.microsoft.com)

第一章:
编写第一个C#代码
{
使用 Console.WriteLine(“Your message here”);
Console、Write 和 Line 首字母大写
使用正确的标点,因为它们在 C# 中扮演特殊角色
如果犯了错误,请将其修复然后重新运行…你不会真正失败

编译器:将代码转化为计算机可以理解的可执行格式

类 拥有 方法,. 是从 类 导航到 方法 的符号,称为成员访问运算符
}

第二章
迈出第一步

第一节:变量声明初始化和数据类型
{
使用C#中的文本值和变量值来存储和检索数据
-创建5个基本数据类型的文本值
string(“”),用于演示的多个字母数字等
char(‘’),单个字母数字字符等,character
int(),整数,integer
decimal(),10进制文本,含小数的十进制文本(123.1m),m为文本后缀
bool类型文本ture or false,不区分大小写,显示统一为首字母大写

-声明和初始化变量
初始化变量 = 声明变量 + 变量赋值

隐式类型本地变量
var关键字创建,其指示C#编译器去根据赋值推断类型;如果不赋值,则无法创建
一旦var产生的隐式变量类型确定了,则永远无法改变(静态方式,即声明时类型是锁定的)
}

第二节:执行基本字符串格式设置
{
创建包含制表符、换行符和其他特殊字符的字符串数据
转义字符序列:+character
例如:\n为添加一个新行,\t为添加英制表符,\u作为添加UTF-16编码字符
+任意符号在str中为保持该符号其str类型
例如列出路径“c:\source\repos”
在字符串文本前加@形成逐字字符串文本,无需转义反斜杠;另外注意()能够在writelines里面跨行并加空格

通过串联将字符串数据合并为新的字符串值
使用+就可以将字符串的变量或者字符串串联起来;
通过合并操作,避免使用中间变量;

通过内插将字符串数据合并为新的字符串值
文本字符串以 为 前 缀 指 示 其 文 字 符 串 模 板 , 中 间 为 变 量 , 这 样 就 可 以 全 部 写 在 “ ” 内 , 少 写 很 多 + 并 便 于 阅 读 合 并 逐 字 文 本 符 号 @ 和 字 符 串 内 插 符 号 为前缀指示其文字符串模板,{}中间为变量,这样就可以全部写在“”内,少写很多+并便于阅读 合并逐字文本符号@和字符串内插符号 +便@可以同时使用;
}

第三节:对数字执行基本运算操作
{
对数字值执行数学运算
int的运算只会包括整数范围内的部分
decimal乘除运算只需要其中至少一位为m类型即可,但是在初始化时应指明为decimal类型
在值之前用()指明目标数据类型来进行强制转换
±*/
余数%

优先级:
在数学中,PEMDAS 是一个首字母缩略词,有助于学生记住执行多个运算的顺序。 此顺序为:

圆括号 §(括号内的内容首先执行)
指数 (E)
乘法 (M) 和除法 (D)(从左至右)
加法 (A) 和减法 (S)(从左至右)
C# 遵循与 PEMDAS 相同的顺序,但指数除外;C#中没有指数运算符,需要用system.Math.Pow()方法

递增递减:利用复合赋值运算符
+= 向左侧变量增加右侧值,专门称为加法赋值运算符(衍生:-=,*=)
++将左侧变量增加1(衍生:–)
定位增量和减量运算符(检索和复合运算符等优先级)
增量和减量运算符都有一个有趣的质量 - 根据其位置,它们会在检索其值之前或之后执行运算。
换而言之,如果你在 ++value 的值之前使用运算符,那么递增会在检索值之前出现。 同样,value++ 会在检索值后递增值。

观察字符串和数值之间的隐式类型转换
混合str和数值时,编译器会努力把不同的数据类型统一,在此处表现为把数字转化为str
但是如果在这种过程中增加对数值运算的括号,则会优先执行括号内的内容(优先级的重要性)

暂时将一种数据类型转换为另一种数据类型
}

第四节 从.NET库类调用方法
{
编写用于调用 .NET 类库中的无状态方法的代码

有些方法是有状态的,而有些方法是无状态的
某些方法的正常工作不依赖于应用程序的当前状态。
换言之,实现 无状态方法 是为了在不引用或更改内存中存储的任何值的情况下正常工作。 无状态方法也称为 静态方法。
例如,Console.WriteLine() 方法不依赖于内存中存储的任何值。
该方法执行其函数并完成工作,而不会以任何方式影响应用程序的状态。
有状态方法是依赖于由以前的已执行代码行存储在内存中的值构建的。
或者,有状态方法通过更新值或将新值存储在内存中来修改应用程序的状态。 它们也称为实例方法。
单个类可支持有状态方法和无状态方法。
但是,需要调用有状态方法时,必须首先创建类的实例,这样方法才能访问状态。

创建 .NET 类库类的新实例,以调用维护状态的方法
类的实例称为对象。 若要创建类的新实例,请使用 new 运算符。
new 运算符执行以下几项重要操作:

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

使用 Intellisense 深入了解方法,包括其重载版本、其返回值类型及其输入参数数据类型

一些方法旨在完成其功能并“安静地”结束。 换言之,它们在完成时不返回值。
这些方法称为 void 方法。
旨在完成后返回值的方法通常是某个操作的结果。
返回值是方法与调用方法的代码进行通信的主要方式。
dice.Next(1, 7);

一些方法旨在接受无输入参数。 这些方法无需额外输入即可完成其任务。
其他方法旨在接受一个或多个输入参数。 输入参数可配置方法执行其工作的方式。
或者,可直接操作输入参数。 我们可通过示例来了解这两种情况。
dice.Next(1, 7);

.NET 类库中的许多方法都有重载的方法签名。
重载方法是通过多个方法签名定义的。
重载方法提供不同的方式调用方法,或提供不同类型的数据。
在某些情况下,可通过给定方法的重载版本,将不同数据类型的值发送到方法中。
int number = 7;
string text = “seven”;

Console.WriteLine(number);
Console.WriteLine();
Console.WriteLine(text);

intellisense就是联想当前输入的字符和相应的.NET库字段匹配
. 符号是成员访问运算符
需要获取.NET库的具体信息,访问docs.microsoft.com 是事实的最终来源
使用 docs.microsoft.com 调查方法的作用、其重载版本、其返回值类型、其输入参数和每个参数所代表的内容,等等
}

第五节 if-elseif-else 决策逻辑
{
使用 if-elseif-else 语句编写评估条件的代码。
if 语句由 3 个部分组成:

if 关键字
用 () 括起来的布尔表达式
布尔表达式是返回布尔值(true 或 false)的任意代码。
合并三个布尔表达式:if ((roll1 == roll2) || (roll2 == roll3) || (roll1 == roll3))
||表示 或
&&表示 与
由大括号 { } 定义的代码块
代码块是包含一行或多行代码的集合,其中代码行由左大括号和右大括号 { } 定义。 它表示在软件系统中用途单一的完整代码单位。
在此情况下,如果布尔表达式为 true,则会在运行时执行代码块中的所有代码行。 反之,如果布尔表达式为 false,则会忽略代码块中的所有代码行。
else和if,else if的等级相同

生成用于评估条件的布尔表达式。
使用逻辑运算符组合布尔表达式。
将代码块嵌套在其他代码块中。
}

第六节 使用数组和foreach语句来存储和循环访问数据序列
{
创建并初始化新数组
数组是可通过单个变量名称进行访问的一系列单个数据元素,也是一种特殊类型的变量。 使用从零开始的数字索引访问数组中的每个元素。
如你所见,数组能够收集相似的数据(这些数据在单个数据结构中共享共同用途或特征),以便于进行处理。
1.声明数组
不要忘了在string后面接[]
string[] fraudulentOrderIDs = new string[3];
new 运算符在可容纳三个字符串值的计算机内存中创建数组的新实例。
2.为数组的元素赋值
从0开始进行赋值。数组本身是非动态增加元素数的,即其所占用内存是固定的,所以不能超过范围
fraudulentOrderIDs[0] = “A123”;
fraudulentOrderIDs[1] = “B456”;
fraudulentOrderIDs[2] = “C789”;
3.获取数组中的元素的值
注意所有数组操作均使用[]来进行索引
Console.WriteLine( " F i r s t : f r a u d u l e n t O r d e r I D s [ 0 ] " ) ; C o n s o l e . W r i t e L i n e ( "First: {fraudulentOrderIDs[0]}"); Console.WriteLine( "First:fraudulentOrderIDs[0]");Console.WriteLine(“Second: {fraudulentOrderIDs[1]}”);
Console.WriteLine($“Third: {fraudulentOrderIDs[2]}”);
4.重新分配数组
对其中的元素进行任意替换
fraudulentOrderIDs[0] = “F000”;

~1 初始化数组
和初始化变量类似,可以直接用带有大括号的语法来初始化数组
string[] fraudulentOrderIDs = { “A123”, “B456”, “C789” };

获取数组大小
fraudulentOrderIDs.Length

在数组中设置并获取值
使用 foreach 语句循环访问数组的每个元素
foreach 语句遍历数组中的每个元素,在其声明下运行代码块,并将临时变量中的值替换为当前循环表示的数组值。
string[] names = { “Bob”, “Conrad”, “Grant” };
//不要忘了foreach的判断中是有数据类型如string的,且其为一种for in循环;但是foreach本身是顺序的;且使用foreach不能重新分配其内部值
foreach (string name in names)
{
Console.WriteLine(name);
}
challenge
string[] fradulentIDs = {“B123”,
“C234”,
“A345”,
“C15”,
“B177”,
“G3003”,
“C235”,
“B179”};

foreach (string ID in fradulentIDs){
if (ID.StartsWith(“B”)){
Console.WriteLine($“New suspected ID found:{ID}.”);
}

}

}

第七节 创建具有约定、空格和注释的易读代码
{
为变量选择一个描述其目的和意图的描述性名称。
变量名称社区约定:
变量名称应使用驼峰式大小写形式,这是一种编写样式,即第一个单词以小写字母开始,后续每个单词的首字母采用大写形式。 例如:string thisIsCamelCase;。
变量名称在应用程序中应具有描述性且有意义。 应为变量选择一个名称,用于表示其将保存的数据类型。
变量名称应是附加在一起的一个或多个完整单词。 请勿使用缩写,因为阅读你代码的人可能不清楚该变量的名称。
变量名称不应包含变量的数据类型。 你可能会看到使用类似 string strMyValue; 样式的一些建议。 这是几年前的热门样式。 但是,大多数开发者不会再遵循此建议。
类也支持可见性修饰符,这些修饰符允许一些值是私有或公共的。 私有成员只能由同一类中的其他成员引用。 公共成员可以在类外部引用。 因此,你可以创建私有字段或公共字段。

使用代码注释暂时指示编译器忽略代码行。
注意:
代码注释不可信任。 通常,开发者会更新其代码,但忘记更新代码注释。 最好使用注释来描述更高级别的想法,请勿添加关于单个代码行如何工作的注释。
代码注释不必要地解释了单独代码行的明显功能。 这些被视为低质量的注释,如果读者不熟悉这些内容,他们可以使用 docs.microsoft.com 或 Intellisense 来查阅。
代码注释未提供代码所解决问题的任何上下文。 这些被视为低质量的注释,因为读者无法了解此代码的用途,尤其是在涉及到更大的系统时。
多行注释:
/*
*/

使用代码注释描述一段代码的更高级别要求或用途。
编写有效使用空格来传达代码行之间关系的代码。
术语“空格”指的是由 space bar 生成的单个空格、由 tab 键生成的制表符以及由 enter 键生成的新行。

C# 编译器会忽略空格
空格对编译器而言不重要。 但是…
正确使用空格可以提高你阅读和理解代码的能力。
提前指导:
每个完整的命令(语句)都属于单独的一行。
如果单个代码行过长,可以将其拆分。 但是,不应随意将单个语句拆分为多行,除非你有充分的理由这样做。
在赋值运算符的左侧和右侧使用空格。
}

第三章
向应用程序添加逻辑
内容:
构建更复杂且更具表现力的布尔表达式
使用代码块控制变量范围和代码的执行路径
使用 switch-case 语句分支代码流
使用 C# 中的 for、while 和 do-while 语句循环访问代码块

第一节
计算布尔表达式以作出决策
{
使用运算符创建用于测试比较和相等性的布尔表达式。
表达式是返回一个值的值(文本或变量)、运算符和方法的任意组合。 语句是 C# 中的完整指令,由一个或多个表达式组成。
C#可以进行字符串级的比较,从而实现逻辑操作
注意C#的语法,所有的方法都以 . 在实例的基础上访问
Console.WriteLine(value1.Trim().ToLower() == value2.Trim().ToLower());
除了常用的比较之外,某些方法返回一个布尔值
Console.WriteLine(pangram.Contains(“fox”));
逻辑或!与&&非||可以添加到布尔表达式中间
注意不要混淆逻辑或!和布尔计算!=

对字符串类使用内置的方法,以更好地计算字符串。
使用否定运算符测试给定条件的相反情况。
使用条件运算符执行内联计算。
条件运算符?:又称为三元条件运算符,用于计算布尔表达式,并返回两个表达式中其中一个的计算结果
? <if condition is true, return this value> : <if condition is false, return this value>
将整个条件运算符语句括在括号中,将会确保运行时不误解我的意图,同时消除临时变量
Console.WriteLine($“Discount: {(saleAmount > 1000 ? 100 : 50)}”);

第二节
使用代码块控制变量范围和逻辑
{
了解在代码块内部和外部声明和初始化变量的影响。
代码块中声明和初始化的变量无法直接在代码块外使用(类似于一种包装)
另外在外部声明变量,而在内部赋值也无法被允许
但是如果在外部初始化变量,则在内部可以重新赋值,并且也会表现在外部
在代码块内部定义变量时,该变量对该代码块本地可见,并且无法从该代码库外部访问该变量。
若要使变量在代码块内部和外部均可见,则必须在代码块外部定义变量。
请勿忘记初始化在代码块中设置其值的任何变量,例如 if 语句。

如果代码块的正文中只有一个代码行,删除 if 语句中的这些代码块,以提高可读性。

标识代码中的命名空间、类和方法。
方法 Main()
类 Program
命名空间 MyNewApp

方法的名称 Main() 是特殊的。 在执行程序时,默认情况下,.NET 运行时将搜索名为 Main() 的方法,以用作该程序的起点或入口点。

类 是方法、属性、事件、字段等成员的容器。 在模块“使用 C# 调用 .NET 类库中的方法”中,你已了解,如果要调用需要状态的方法(或实例方法),则必须使用 new 关键字创建类的实例。 否则,无需先创建类的实例即可调用不具有状态的方法(或静态方法)。

命名空间 可消除类名的歧义。 在模块“使用 C# 调用 .NET 类库中的方法”中,你已了解,.NET 类库中具有多个类,因此可能会有两个类具有相同的名称。 命名空间可确保还可以通过指定命名空间来指示编译器要使用的类和方法。

public关键字为可访问性修饰符,使得方法可以被同一上级类下的其他方法引用

了解将方法移动到新类以及将类移动到新命名空间中的操作如何影响代码的可见性。
了解如何使用 using 语句指示编译器去何处查找代码中引用的类。

命名空间可消除具有相同名称的两个类的歧义。
}

第三节
使用switch-case 结构将代码流分支
{
使用 switch-case 结构将一个变量或表达式与多个可能结果进行匹配。
代码块中的一个或多个 switch 部分。 每个 switch 部分都包含一个或多个标签。 标签以关键字 case 和匹配模式开头。 运行时将匹配表达式的值与每个匹配模式进行比较,直到找到匹配为止。
default 标签是可选的,不一定要在其他条件之后定义它。 但是,大多数开发者会选择将其放在最后,因为它的意义就在于“防错”或“无奈之选”。
可以将两个case和一个输出绑定
Switch(employeeNum)
{
case 100:
case 200:
title = “Senior Associate”;
break;
}
将使用 if-elseif-else 结构的代码转换为 switch-case 结构。
}

第四节
使用for 语句循环访问代码块
{
使用 for 语句循环访问代码块。
for 语句有六个部分。

for 关键字
用于定义 for 迭代条件的一组括号。 它包含三个不同的部分,在语句运算符的末尾处由分号分隔。
第一部分定义并初始化迭代器变量。 在本示例中:int i = 0。 文档将此部分称为 初始化表达式。
第二部分定义完成条件。 在本示例中:i < 10。 换言之,只要 i 小于 10,运行时就会持续遍历 for 语句下代码块中的代码。 一旦 i 大于或等于 10,运行时就会执行 for 语句代码块后面的代码。 文档将此部分称为 条件。
第三部分定义每次迭代后要执行的操作。 在这种情况下,每次迭代后,i++ 会将 i 的值增加 1。 文档将此部分称为 迭代器。
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
最后来说说代码块。 这是每次迭代要执行的代码。 请注意,i 的值是在代码块内引用的。 文档将此部分称为 主体。
如果需要根据某种条件提前退出迭代语句,该怎么办? 可以使用 break 关键字。注意,end、exit不是C#中的关键字
相比于foreach,for可以直接控制数组中的每一项

修改 .NET 运行时执行循环逻辑的方式并更改迭代器的值、条件和模式。
}

第五节
使用 do-while 和 while 语句在代码中添加循环逻辑
{
编写代码,以使用 do-while 语句循环访问代码块。
当指定布尔表达式的计算结果为 true 时,do 语句执行语句或语句块。 由于该表达式在每次执行循环之后计算,因此 do-while 循环将执行一次或多次。
Random random = new Random();
int current = 0;

do
{
current = random.Next(1, 11);
Console.WriteLine(current);
} while (current != 7);
区分于foreach和for,do while依靠于代码块内的代码影响是否继续进行循环,而前者则依赖于外部因素

在某些情况下,我们想要不运行代码块中剩余代码,并继续进行下一次迭代。 可以使用 continue 语句来执行此操作。
Random random = new Random();
int current = random.Next(1, 11);

do
{
current = random.Next(1, 11);

if (current >= 8) continue;

Console.WriteLine(current);

} while (current != 7);
与break相比,break完全杀死了循环,而continue则强制重新进行循环

编写代码,以使用 while 语句循环访问代码块。
使用 continue 语句直接跳到布尔计算结果。

challenge小游戏
int healthpointHero = 10;
int healthpointMonster = 10;
Random attackDamage = new Random();
int heroDamage = 0;
int monsterDamage = 0;
string winner = “”;
string suggest = “”;

Console.WriteLine("<<

// combat process
do
{
//hero attack
Console.WriteLine("\n<<Hero’s turn!>>");
heroDamage = attackDamage.Next(1,10);
healthpointMonster = healthpointMonster - heroDamage;
if (heroDamage >=5 )
Console.WriteLine("***Hero caused critical attack!***");
if (healthpointMonster <= 0)
{ Console.WriteLine($“Hero attacked monster! Caused {heroDamage} point damage! Monster left 0 HP! Monster is killed.”);

    break;
}
else
    Console.WriteLine($"Hero attacked monster! Caused {heroDamage} point damage! Monster left {healthpointMonster} HP.");

Console.WriteLine("\n<<Monster's turn!>>");
monsterDamage =  attackDamage.Next(1,10);
healthpointHero = healthpointHero - monsterDamage;
if (monsterDamage >=5 )
     Console.WriteLine("***Monster caused critical attack!***");
if (healthpointHero <= 0)
{    Console.WriteLine($"Monster attacked hero! Caused {monsterDamage} point damage! Hero left 0 HP! Hero is down.");

    break;
}
else
    Console.WriteLine($"Monster attacked hero! Caused {monsterDamage} point damage! Hero left {healthpointHero} HP.");

} while (true);

if (healthpointHero >0)
{
winner = “Hero”;
suggest = “Congradulations!”;
}
else
{
winner = “Monster”;
suggest = “Work harder!”;
}
Console.Write($"\n<<<The winner is {winner}, {suggest}>>>");
}

第三章
处理数据

第一节
选择正确的数据类型
{
了解值类型和引用类型之间的差异。
数据类型是一种编程语言构造,用于定义要为某个值保留多少内存。 这就是我们有如此多的数据类型的原因:编程语言的设计人员知道数据类型将用于众多不同的应用程序和数据大小。
数据类型有两种基本类别:值类型和引用类型。 值类型和引用类型之间的基本差异涉及到这些值在应用程序执行时临时存储在内存中的位置。
整型类型是一种简单的值类型,表示整数。整型类型有两个子类别:有符号和无符号整型类型。
有符号整型类型的最大最小值属性:
Console.WriteLine(“Signed integral types:”);

Console.WriteLine( " s b y t e : s b y t e . M i n V a l u e t o s b y t e . M a x V a l u e " ) ; C o n s o l e . W r i t e L i n e ( "sbyte : {sbyte.MinValue} to {sbyte.MaxValue}"); Console.WriteLine( "sbyte:sbyte.MinValuetosbyte.MaxValue");Console.WriteLine(“short : {short.MinValue} to {short.MaxValue}”);
Console.WriteLine( " i n t : i n t . M i n V a l u e t o i n t . M a x V a l u e " ) ; C o n s o l e . W r i t e L i n e ( "int : {int.MinValue} to {int.MaxValue}"); Console.WriteLine( "int:int.MinValuetoint.MaxValue");Console.WriteLine(“long : {long.MinValue} to {long.MaxValue}”);
无符号整型类型的最大最小值属性:
Console.WriteLine("");
Console.WriteLine(“Unsigned integral types:”);

Console.WriteLine( " b y t e : b y t e . M i n V a l u e t o b y t e . M a x V a l u e " ) ; C o n s o l e . W r i t e L i n e ( "byte : {byte.MinValue} to {byte.MaxValue}"); Console.WriteLine( "byte:byte.MinValuetobyte.MaxValue");Console.WriteLine(“ushort : {ushort.MinValue} to {ushort.MaxValue}”);
Console.WriteLine( " u i n t : u i n t . M i n V a l u e t o u i n t . M a x V a l u e " ) ; C o n s o l e . W r i t e L i n e ( "uint : {uint.MinValue} to {uint.MaxValue}"); Console.WriteLine( "uint:uint.MinValuetouint.MaxValue");Console.WriteLine(“ulong : {ulong.MinValue} to {ulong.MaxValue}”);
浮点型是一种简单的值类型,表示小数。
首先,必须考虑每个类型允许的精度位数。 精度是小数点后可以存储的值的数目。
其次,必须考虑值的存储方式以及该方式对值的准确度造成的影响。 换句话说,float 和 double 值在内部以二进制 (base 2) 格式存储,而 decimal 以十进制 (base 10) 格式存储。 为什么了解这一点很重要?
通常,二进制浮点值的数学运算结果是实际值的近似值。 因此,float 和 double 非常有用,因为可以使用较小的内存占用量来存储较大的数字,但仅当近似值有用时才应使用此数据类型。 例如,在计算视频游戏中武器的爆炸区域时,偏离千分之几就已非常接近实际值。
decimal 类型的每个值都具有比较大的内存占用量,但执行数学运算可提供更精确的结果。 因此,在处理财务数据时或在任何需要通过计算得出精确结果的场景下,应使用 decimal。
浮点型的最大最小值:
Console.WriteLine("");
Console.WriteLine(“Floating point types:”);
Console.WriteLine( " f l o a t : f l o a t . M i n V a l u e t o f l o a t . M a x V a l u e ( w i t h   6 − 9 d i g i t s o f p r e c i s i o n ) " ) ; C o n s o l e . W r i t e L i n e ( "float : {float.MinValue} to {float.MaxValue} (with ~6-9 digits of precision)"); Console.WriteLine( "float:float.MinValuetofloat.MaxValue(with 69digitsofprecision)");Console.WriteLine(“double : {double.MinValue} to {double.MaxValue} (with ~15-17 digits of precision)”);
Console.WriteLine($“decimal: {decimal.MinValue} to {decimal.MaxValue} (with 28-29 digits of precision)”);
引用类型包括数组、类和字符串。
值类型变量会将其值直接存储在名为堆栈(stack)的存储区域中。 堆栈是为 CPU 上当前运行的代码分配的内存(也称为堆栈帧或激活帧)。 堆栈帧执行完毕后,堆栈中的值将被删除。
引用类型变量会将其值存储在名为堆(heap)的单独内存区域中。 堆是一个内存区域,由操作系统上运行的多个应用程序同时共享。 .NET 运行时与操作系统进行通信以确定可用的内存地址,并请求可存储该值的地址。
.NET 运行时会存储值,然后将内存地址返回给变量。 当代码使用变量时,.NET 运行时会无缝查找变量中存储的地址,并检索其中存储的值。
int 阵列的元素默认为值 0,因此它是 int 的默认值。
string 数据类型也是引用类型。 你可能会奇怪为什么我们在声明字符串时,不使用 new 操作符。 这仅仅是因为 C# 设计者想要提供一种便利。
由于可供选择的数据类型太多,针对特定情况应采用哪种标准选择适当的数据类型呢?

在评估这些选项时,必须考虑一些重要的注意事项。 正确答案通常不止一个,但有些答案比其他答案更正确。
1.请选择具有所需值范围的数据类型作为应用程序中的内置约束。
2.不要根据你感觉将会影响性能的因素选择数据类型(至少在开始时不要这么做)。
3.根据与库函数的交互以及输入和输出的数据类型来选择数据类型。
4.根据对其他系统的影响(例如,在数据库中长期存储)选择数据类型。
5.如有疑问,请继续使用基本类型。
6.针对特殊情况选择专门的复杂类型。

描述多种新数值数据类型的属性,包括新的整型类型和浮点型类型。
编写代码,用于返回数值数据类型可存储的最大值和最小值。
使用 new 关键字创建引用类型的新实例。
确定应该为给定应用程序选择的数据类型。

}

第二节
使用强制转换和转换方法转换数据类型
{
使用强制转换运算符将值强制转换为其他数据类型。
有多种方法可以执行数据类型转换或强制转换。 选择哪种方法取决于你对两个重要问题的回答:

问题 1:对于不同的值,尝试更改值的数据类型是否可能在运行时引发异常?
int first = 2;
string second = “4”;
string result = first + second;
Console.WriteLine(result);
C# 编译器会在操作过程中发现潜在问题。 变量 second 的类型为 string,因此可能会将其设置为不同的值,如 “hello”。 如果 C# 编译器尝试将 “hello” 转换为数字,则会在运行时引发异常。 为避免这种情况,C# 编译器不会隐式执行从 string 到 int 的转换。

从 C# 编译器的角度来看,更安全的操作是将 int 转换为 string 并改为执行串联。
若要执行数据转换,你可以使用下列方法之一:

对数据类型使用帮助程序方法
对变量使用帮助程序方法
使用 Convert 类的方法

问题 2:对于不同的值,尝试更改值的数据类型是否可能导致信息丢失?
术语“扩大转换”表示你试图将值从一种可以保留较少信息的数据类型转换为一种可保留较多信息的数据类型。 在这种情况下,你不会丢失任何信息。 因此,其中一个示例是转换存储在 int 类型的变量中的值,并将该值转换为 decimal 类型的变量。
如果你了解需要执行扩大转换,则可以依赖于隐式转换。 隐式转换由编译器处理。
int myInt = 3;
Console.WriteLine($“int: {myInt}”);

decimal myDecimal = myInt;
Console.WriteLine(KaTeX parse error: Expected 'EOF', got '#' at position 221: …转换。 强制转换是一种针对 C#̲ 编译器的指令,即你知道可能发…“decimal: {myDecimal}”);

int myInt = (int)myDecimal;
Console.WriteLine($“int: {myInt}”);
具体转换影响参照
https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/conversion-tables
ToString()方法可以将数字转化为字符串
每个数据类型变量都具有 ToString() 方法。 ToString() 方法的作用取决于它在给定类型上的实现方式。 但在大多数基元中,该方法执行扩大转换。 尽管这并不是绝对必要的(因为在大多数情况下我们可以依赖于隐式转换),但它可以向其他开发者传递这样的信息,即你了解正在执行的操作,并且是有意为之的。
int first = 5;
int second = 7;
string message = first.ToString() + second.ToString();
Console.WriteLine(message);
大部分数字数据类型都具有Parse()方法,可以将字符串转化为给定的数据类型。
string first = “5”;
string second = “7”;
int sum = int.Parse(first) + int.Parse(second);
Console.WriteLine(sum);
由于Parse在规划数据类型有误时可能会引起异常,所以建议使用TryParse()
Convert 类有许多可用于将值从一种类型转换为另一种类型的帮助程序方法。 在下面的代码示例中,我们将两个字符串转换为 int 类型的值。
string value1 = “5”;
string value2 = “7”;
int result = Convert.ToInt32(value1) * Convert.ToInt32(value2);
Console.WriteLine(result);
我们在此处使用带有字符串的 Convert.ToInt32() 方法,但你应该尽可能使用 TryParse()。
那么,在什么情况下我们应该使用 Convert 类? Convert 类非常适用于将小数数字转换为整数 (int),因为它按预期方式向上舍入。例如有的强制转换会直接将小数部分删去

使用转换方法将值转换为其他数据类型。
在执行强制转换或转换操作时防止数据丢失。
使用 TryParse() 方法安全地将字符串转换为数字数据类型。
TryParse() 方法可同时执行多项操作:

它会尝试将字符串分析成给定的数字数据类型。
如果成功,它会将转换后的值存储在 out 参数中。
它会返回布尔值来指示操作是否成功。
什么是 out 参数?
方法可在完成时返回值或返回“void”,后者意味着不返回值。 方法还可以选择性地返回所有参数的值,这些值的定义与任何其他输入参数一样,但包含 out 关键字。

使用 out 参数调用方法时,还必须在变量前使用关键字 out,以便保存值。 因此,在调用将用于存储由方法返回的 out 参数值的方法之前,必须先定义一个变量。 然后,即可在代码的其余部分使用包含 out 参数的值。
string value = “102”;
int result = 0;
if (int.TryParse(value, out result))
{
Console.WriteLine($“Measurement: {result}”);
}
else
{
Console.WriteLine(“Unable to report the measurement.”);
}
转换成功,则值将被存在result中,并返回ture;否则返回false。

挑战1
string[] values = { “12.3”, “45”, “ABC”, “11”, “DEF” };

decimal total = 0m;
string message = “”;

foreach (var value in values)
{
decimal number;
if (decimal.TryParse(value, out number))
{
total += number;
} else
{
message += value;
}
}

Console.WriteLine( " M e s s a g e : m e s s a g e " ) ; C o n s o l e . W r i t e L i n e ( "Message: {message}"); Console.WriteLine( "Message:message");Console.WriteLine(“Total: {total}”);

总结:
强制转换限制于数字数据类型之间,且有收缩转换风险
ToString是具有数字数据类型的变量的方法,将其转换为string
Parse和TryParse是数字数据类型的方法,将字符串变量转化为数字数据类型
Convert是单独的方法,可以按照其所具有的具体方法进行各项转换
}

第三节
使用帮助器方法对数组执行操作
{
排列和反向排列数组元素。
Sort() 和 Reverse()

Array 类包含一些方法,可用于操纵数组的内容、排列方式和大小。
string[] pallets = { “B14”, “A11”, “B12”, “A13” };

Console.WriteLine(“Sorted…”);
Array.Sort(pallets);
foreach (var pallet in pallets)
{
Console.WriteLine($"-- {pallet}");
}

Console.WriteLine("");
Console.WriteLine(“Reversed…”);
Array.Reverse(pallets);
foreach (var pallete in pallets)
{
Console.WriteLine($"-- {pallete}");
}
关注 Array.Sort(pallets); 所在的代码行。 在此,使用 Array 类的 Sort() 方法,按字母顺序对数组中的项进行排序。
通过调用 Array.Reverse() 方法来反转托盘顺序。注意:Array.Reverse()是直接作用于变量上的,不会输出结果,所以要单列一行执行;

Clear() 和 Resize()
使用 Array.Clear() 方法可删除数组中特定元素的内容,使用 Array.Resize() 方法可在数组中添加或删除元素。
string[] pallets = { “B14”, “A11”, “B12”, “A13” };
Console.WriteLine("");

Array.Clear(pallets, 0, 2);
Console.WriteLine(KaTeX parse error: Expected '}', got 'EOF' at end of input: …sole.WriteLine("-- {pallet}");
}
从索引 0 开始,清除 2 个元素。不含2位置(即第三个)元素
空字符串与 null
使用 Array.Clear() 时,被清除的元素不再引用内存中的字符串。 事实上,该元素不指向任何内容。 这是一个重要的区别,最初可能会难以理解。
即null并不是指在数据的内存上,这部分被抹除了,而是指针消失了
string[] pallets = { “B14”, “A11”, “B12”, “A13” };
Console.WriteLine("");

Array.Clear(pallets, 0, 2);
Console.WriteLine(KaTeX parse error: Expected '}', got 'EOF' at end of input: …sole.WriteLine("-- {pallet}");
}

Console.WriteLine("");
Array.Resize(ref pallets, 6);
Console.WriteLine($“Resizing 6 … count: {pallets.Length}”);

pallets[4] = “C01”;
pallets[5] = “C02”;

foreach (var pallet in pallets)
{
Console.WriteLine($"-- {pallet}");
}
关注 Array.Resize(ref pallets, 6); 所在的行。 在此,我们将调用通过引用(使用 ref 关键字)传入 pallets 数组的 Resize() 方法。
调整数组大小以删除元素
Array.Resize(ref pallets, 3);
将会删除后三个元素
但是没有方法自动从数组中删去空元素
如果 Array.Resize() 方法不能从数组中删除空元素,是否存在其他可自动执行此操作的帮助器方法? 没有。 实现此操作的最佳方式是,通过循环访问每个项并使一个变量(计数器)递增,对非 null 元素进行计数。 接下来,创建另一个与计数器变量大小相同的数组。 最后,循环访问原始数组中的每个元素,并将非 null 值复制到新数组中。

Split() 和 Join()
字符串的数组方法
使用 ToCharArray() 反向编码字符串
string value = “abc123”;
char[] valueArray = value.ToCharArray();
Array.Reverse(valueArray);
string result = new string(valueArray);
Console.WriteLine(result);
表达式 new string(valueArray) 会新建 System.String 类的空实例(与 C# 中的 string 数据类型相同),并以构造函数的形式传入字符数组。

使用 String 类的 Join() 方法,传入要用于分段的字符(逗号)和数组本身
string value = “abc123”;
char[] valueArray = value.ToCharArray();
Array.Reverse(valueArray);
// string result = new string(valueArray);
string result = String.Join(",", valueArray);
Console.WriteLine(result);
使用可用于字符串类型变量的 Split() 方法来创建字符串数组。使用逗号作为分隔符,将一个长字符串拆分为较小字符串。
string value = “abc123”;
char[] valueArray = value.ToCharArray();
Array.Reverse(valueArray);
// string result = new string(valueArray);
string result = String.Join(",", valueArray);
Console.WriteLine(result);

string[] items = result.Split(’,’);
foreach (string item in items)
{
Console.WriteLine(item);
}
注意:在Join用双引号,Split用单引号,前者是string的方法,后者是变量实例的方法

清除数组元素及调整其大小。
将字符串拆分为字符串或字符 (char) 的数组。
将数组元素加入字符串。

挑战1
string pangram = “The quick brown fox jumps over the lazy dog”;
string[] pangramList = pangram.Split(’ ');
string[] pangramListNew = new string[pangramList.Length];
string pangramnew;
for (int i=0;i<pangramList.Length;i++)
{
string word = pangramList[i];
char[] wordArray = word.ToCharArray();
Array.Reverse(wordArray);
pangramListNew[i] = new string(wordArray);

}
pangramnew = String.Join(" ",pangramListNew);
Console.WriteLine(pangramnew);
}

第四节
在 C# 中设置字母数字数据的格式以供展示
{
数据输入,包括用户通过键盘、鼠标、设备或由其他软件系统通过网络请求键入的数据
数据处理,包括决策逻辑、操作数据、执行计算等
数据输出,包括通过命令行消息、窗口、网页、将已处理的数据保存到文件、将其发送到网络服务等方式向最终用户展示

使用字符转义序列向字符串添加制表符、新行和 Unicode 字符
创建逐字字符串文本,并转义常见字符,如反斜杠和双引号
使用复合格式设置和字符串内插将模板与变量合并
复合格式设置在字符串中使用带编号的占位符。 在运行时,大括号内的所有内容都将解析为一个值,该值也是根据大括号的位置传入的。
string first = “Hello”;
string second = “World”;
string result = string.Format("{0} {1}!", first, second);
Console.WriteLine(result);
给定数据类型的数据类型和变量具有内置“帮助程序方法”,可简化某些任务。
文本字符串 “{0} {1}!” 构成一个模板,其中部分内容将在运行时被替换。
标记 {0} 替换为字符串模板后的第一个参数,即 first 变量的值。
标记 {1} 替换为字符串模板后的第二个参数,即 second 变量的值。
字符串内插是一种可简化复合格式设置的较新方法。 如果通过书籍和联机方式查看代码示例,可能会发现使用了两种方法,但通常应首选字符串内插。
string first = “Hello”;
string second = “World”;
Console.WriteLine( " f i r s t s e c o n d ! " ) ; C o n s o l e . W r i t e L i n e ( "{first} {second}!"); Console.WriteLine( "firstsecond!");Console.WriteLine("{second} {first}!");
Console.WriteLine( " f i r s t f i r s t f i r s t ! " ) ; 设 置 货 币 格 式 复 合 格 式 设 置 和 字 符 串 内 插 可 用 于 根 据 特 定 语 言 和 区 域 性 设 置 显 示 值 的 格 式 。 在 下 面 的 示 例 中 , : C 货 币 格 式 说 明 符 用 于 将 p r i c e 和 d i s c o u n t 变 量 以 货 币 形 式 显 示 。 d e c i m a l p r i c e = 123.45 m ; i n t d i s c o u n t = 50 ; C o n s o l e . W r i t e L i n e ( "{first} {first} {first}!"); 设置货币格式 复合格式设置和字符串内插可用于根据特定语言和区域性设置显示值的格式。 在下面的示例中,:C 货币格式说明符用于将 price 和 discount 变量以货币形式显示。 decimal price = 123.45m; int discount = 50; Console.WriteLine( "firstfirstfirst!");:Cpricediscountdecimalprice=123.45m;intdiscount=50;Console.WriteLine(“Price: {price:C} (Save {discount:C})”);
输出符号为:¤。但是在美国,会输出$
设置数值格式
处理数字数据时,可能需要通过包含逗号来分隔千位、百万位、十亿位等来设置数字格式,提高其可读性。
decimal measurement = 123456.78912m;
Console.WriteLine( " M e a s u r e m e n t : m e a s u r e m e n t : N u n i t s " ) ; N 数 值 格 式 说 明 符 默 认 仅 显 示 小 数 点 后 两 位 数 字 。 如 果 要 以 更 高 的 精 度 显 示 , 可 通 过 在 说 明 符 后 面 添 加 数 字 来 实 现 。 d e c i m a l m e a s u r e m e n t = 123456.78912 m ; C o n s o l e . W r i t e L i n e ( "Measurement: {measurement:N} units"); N 数值格式说明符默认仅显示小数点后两位数字。 如果要以更高的精度显示,可通过在说明符后面添加数字来实现。 decimal measurement = 123456.78912m; Console.WriteLine( "Measurement:measurement:Nunits");Ndecimalmeasurement=123456.78912m;Console.WriteLine(“Measurement: {measurement:N4} units”);
使用 P 格式说明符设置百分比的格式。 之后添加一个数字来控制小数点后显示位数。
decimal tax = .36785m;
Console.WriteLine($“Tax rate: {tax:P2}”);

包括百分比、货币和数字的各种格式说明符
下面是这些内置方法类别的简要列表,你可以了解可用的类别。

添加空白进行格式设置的方法(PadLeft()、PadRight())
string input = “Pad this”;
Console.WriteLine(input.PadRight(12));
Console.WriteLine(input.PadLeft(12, ‘-’));
Console.WriteLine(input.PadRight(12, ‘-’));
///
string paymentId = “769”;
string payeeName = “Mr. Stephen Ortega”;
string paymentAmount = “$5,000.00”;

var formattedLine = paymentId.PadRight(6);
formattedLine += payeeName.PadRight(24);
formattedLine += paymentAmount.PadLeft(10);

Console.WriteLine(“1234567890123456789012345678901234567890”);
Console.WriteLine(formattedLine);
上面的数字行用于方便视觉计算列;

比较两个字符串或辅助比较的方法(Trim()、TrimStart()、TrimEnd()、GetHashcode()、Length 属性)

帮助确定字符串内部内容,甚至只检索部分字符串的方法(Contains()、StartsWith()、EndsWith()``Substring())

通过替换、插入或删除部件来更改字符串内容的方法(Replace()、Insert()、Remove())

将字符串转换为字符串或字符数组的方法(Split()、ToCharArray())

挑战
string customerName = “Mr. Jones”;

string currentProduct = “Magic Yield”;
int currentShares = 2975000;
decimal currentReturn = 0.1275m;
decimal currentProfit = 55000000.0m;

string newProduct = “Glorious Future”;
decimal newReturn = 0.13125m;
decimal newProfit = 63000000.0m;

// Your logic here
Console.WriteLine( " D e a r c u s t o m e r N a m e , " ) ; C o n s o l e . W r i t e L i n e ( "Dear {customerName},"); Console.WriteLine( "DearcustomerName,");Console.WriteLine(“As a customer of our {currentProduct} offering we are excited to tell you about a new financial product that would dramatically increase your return.”);
Console.WriteLine(KaTeX parse error: Undefined control sequence: \nCurrently at position 2: "\̲n̲C̲u̲r̲r̲e̲n̲t̲l̲y̲, you own {curr…"\nOur new product, {newProduct} offers a return of {newReturn:P2}. Given your current volume, your potential profit would be {newProfit:C}.");

Console.WriteLine("\nHere’s a quick comparison:\n");

string comparisonMessage = “”;

// Your logic here
comparisonMessage = currentProduct.PadRight(20) + $"{currentReturn:p2}".PadRight(10) + $"{currentProfit:C}".PadLeft(10) + “\n” +
newProduct.PadRight(20) + $"{newReturn:p2}".PadRight(10) + $"{newProfit:C}".PadLeft(10);
Console.WriteLine(comparisonMessage);
}

第五节
使用 C# 中的内置字符串数据类型方法修改字符串内容
{
标识字符或字符串在另一个字符串内的位置
使用字符串的 IndexOf() 和 Substring() 帮助程序方法
在本练习中,你将使用 IndexOf() 方法及其变体(包括 IndexOfAny() 和 LastIndexOf()来查找某个字符或字符串在较大字符串中的位置。

确定位置后,即可使用 Substring() 方法返回该位置后此字符串的其余部分。

或者,我们可以使用 Substring() 方法的重载版本来设置在该位置后要返回的字符数(长度)。
string message = “What is the value between the tags?”;

int openingPosition = message.IndexOf("");
int closingPosition = message.IndexOf("");

openingPosition += 6;
int length = closingPosition - openingPosition;
Console.WriteLine(message.Substring(openingPosition, length));
string message = “What is the value between the tags?”;

int openingPosition = message.IndexOf("");
int closingPosition = message.IndexOf("");

openingPosition += 6;
int length = closingPosition - openingPosition;
Console.WriteLine(message.Substring(openingPosition, length));
应该将常数与 const 关键字一起使用。 通过常数可定义和初始化一个变量,该变量的值永远不会更改。 这样,只要需要该值,就可以在代码的其余部分中使用该常量。 这可确保仅定义一次该值,并且编译器将捕获拼写错误的 const 变量。
初始化后无法更改即为常数变量
string message = “What is the value between the tags?”;

const string openSpan = “”;
const string closeSpan = “”;

int openingPosition = message.IndexOf(openSpan);
int closingPosition = message.IndexOf(closeSpan);

openingPosition += openSpan.Length;
int length = closingPosition - openingPosition;
Console.WriteLine(message.Substring(openingPosition, length));
捕获拼写错误这个功能很重要
LastIndexOf()
string message = “(What if) I am (only interested) in the last (set of parentheses)?”;
int openingPosition = message.LastIndexOf(’(’);

openingPosition += 1;
int closingPosition = message.LastIndexOf(’)’);
int length = closingPosition - openingPosition;
Console.WriteLine(message.Substring(openingPosition, length));
提取所有的括号间的值
string message = “(What if) there are (more than) one (set of parentheses)?”;
while (true)
{
int openingPosition = message.IndexOf(’(’);
if (openingPosition == -1) break;

openingPosition += 1;
int closingPosition = message.IndexOf(')');
int length = closingPosition - openingPosition;
Console.WriteLine(message.Substring(openingPosition, length));

// Note how we use the overload of Substring to return only the remaining 
// unprocessed message:
message = message.Substring(closingPosition + 1);

}
使用IndexOfAny()循环寻找各种括号内的值
string message = “(What if) I have [different symbols] but every {open symbol} needs a [matching closing symbol]?”;

// The IndexOfAny() helper method requires a char array of characters
// we want to look for:

char[] openSymbols = { ‘[’, ‘{’, ‘(’ };

// We’ll use a slightly different technique for iterating through the
// characters in the string. This time, we’ll use the closing position
// of the previous iteration as the starting index for the next open
// symbol. So, we need to initialize the closingPosition variable
// to zero:

int closingPosition = 0;

while (true)
{
int openingPosition = message.IndexOfAny(openSymbols, closingPosition);

if (openingPosition == -1) break;

string currentSymbol = message.Substring(openingPosition, 1);

// Now we must find the matching closing symbol
char matchingSymbol = ' ';

switch (currentSymbol)
{
    case "[":
        matchingSymbol = ']';
        break;
    case "{":
        matchingSymbol = '}';
        break;
    case "(":
        matchingSymbol = ')';
        break;
}

// Finally, use the techniques we've already learned to display the sub-string:

openingPosition += 1;
closingPosition = message.IndexOf(matchingSymbol, openingPosition);

int length = closingPosition - openingPosition;
Console.WriteLine(message.Substring(openingPosition, length));

}

提取部分字符串
删除部分字符串
使用 Remove() 和 Replace() 方法
使用 Remove() 方法从字符串中删除字符,并使用 Replace() 方法替换字符。
Remove()需要提供被删去部分字符串的起点和长度
string data = “12345John Smith 5000 3 “;
string updatedData = data.Remove(5, 20);
Console.WriteLine(updatedData);
Replace()需要提供被替换和替换的字符串
string message = “This–is–ex-amp-le–da-ta”;
message = message.Replace(”–”, " “);
message = message.Replace(”-", “”);
Console.WriteLine(message);

将字符串中的值替换为其他值
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值