字符串插值
通过使用字符串插值格式,字符串可以支持嵌入的表达式。
基本用法
字符串插值语法在一个字符串字面量前加上一个“$”符号前缀,然后将表达式嵌入大括号中。
System.Console.WriteLine($"Your full name is {firstName} {lastName}."); |
字符串字面量可以通过在“@”符号前加上“$”符号的字符串插值组合而成。
System.Console.WriteLine($@"Your full name is: |
如果在代码中,在大括号后换行,就可以避免输出被分为两行。
System.Console.WriteLine($@"Your full name is: { |
深入理解
字符串插值是调用string.Format()方法的简写。
System.Console.WriteLine($"Your full name is {firstName} {lastName}.") |
using和using static
using static指令必须放在文件的最开始。以后每次使用可以省略命名空间和类型名的前缀。
using static System.Console; |
换行符
输出新行所需的字符串取决于执行代码的操作系统。
Windows平台换行符:\r\n
UNIX系统:\n
System.Environment.NewLine可用于创建空行。
System.Console.WriteLine("Hello world") |
隐式局部变量和匿名类型
C#3.0新增了关键字var来声明隐式类型的局部变量。var可以配合匿名类型使用。
匿名类型是在方法内部动态声明的数据类型,而不是通过显式的类定义来声明的。
class Program |
可空修饰符
一般情况下,不能将null值赋给值类型。但可以用可空修饰符“?”声明可以存储null的变量。
static void Main() |
数据类型之间转换
checked和unchecked转换
C#提供了特殊关键字来标识代码块,指出假如目标数据类型太小,以至于容不下赋值的数据,会发生什么情况。
将发生溢出的代码放到一个checked块中,或者在编译时使用checked选项,就会在运行时引发System.OverflowException异常。
static void Main(string[] args) |
若把发生溢出的代码放到unchecked块中,它强制不进行溢出检查,不会为块中溢出的赋值引发异常。
unchecked |
TryParse
C#2.0开始,所有基础元数据数值类型都包含静态方法TryParse(),转换失败的时候,不引发异常,而是返回false。
double number; |
数组
default关键字
使用default操作符显式地获取任何数据类型的默认值
int count = default(int);//0 |
注意:从C#2.0开始可以使用default()表达式判断数据类型的默认值。default()获取数据类型作为参数。
- 引用类型(如string)默认值为null。
- 数值类型默认值为0。
- bool类型默认值为false。
- char默认值为\0。
二维数组
声明多维数组要使用逗号,逗号数量+1=维数。
声明二维数组
int[,] cells = int[3,3]; |
初始化二维整数数组
int[,] cells = { |
交错数组
多维数组的每一维的大小都必须一致。交错数组是由数组构成的数组,不需要具有一致的大小。
初始化交错数组
int[][] cells = { |
注意:交错数组要求对数组中的数组进行实例化。
数组实例方法
获取特定维的大小:GetLength()
bool[,,] cells; |
表示第一维上的元素个数为2。
获取整个数组的维数:Rank
System.Console.WriteLine(cells.Rank);//Display 3 |
表示该数组是三维数组。
注意:要创建数组的全新副本,需要使用数组的Clone()方法。该方法返回数组的一个副本。
操作符
空接合操作符
空接合操作符??是二元操作符,支持短路求值。表示“如果这个值为空,就使用另一个值”。
string fileName = GetFileName(); |
注意:空接合操作符是C#2.0和可空值类型一起引入的。它的操作数既可以是可空值类型,也可以是引用类型。
null条件操作符
在调用值为null的方法时,运行时会抛出一个System.NullReferenceException的异常。C#6.0引入了一种简化的null条件操作符?.来替代调用成员前进行null值检查的操作。
class Program |
注意:当调用的成员返回的是一个值类型时,它总是返回该类型的可为空的版本。
例如,args?.Length返回int?,而不是简单的int。
类似的,args[0]?.ToLower().StartWith(“file:”)返回bool?。
按位操作符
移位操作符
左移位:<<
左移时,所有位都向左移动由操作符右侧的操作数指定的位数。移位后在右边留下的空位填充0。
右移位:>>
右移位原理和左移位相似,是朝相反方向移位,但如果是负数,左侧填充1而不是0。
复合移位和赋值操作符:<<=和>>=
int x; |
按位操作符
对两个操作数执行逐位的逻辑运算。比如AND、OR和XOR等,使用&、|和^操作符实现。
byte and, or, xor; |
上述代码中的7称为掩码,作用是通过特定的操作符表达式,公开或消除第一个操作数中特定的位。
注意:AND和OR操作符的按位版本(&和|)不会进行短路求值。
获取二进制形式的字符串表示
class BinaryConverter |
按位赋值操作符
按位操作符可以和赋值操作符合并,即&=、|=和^=。
byte and = 12, or = 12, xor = 12; |
按位取反操作符
按位取反操作符(~)是对操作数的每一位取反。
C#预处理指令
控制流语句中的条件表达式在运行时求值。相反,C#预处理器在编译时调用。预处理指令告诉C#编译器要编译哪些代码,并指出如何处理代码中的特定错误和警告。C#预处理指令还可告诉C#编译器有关代码组织的信息。
每个预处理指令都以#开头,而且必须在一行中写完。换行符标志着预处理指令的结束。
语句或表达式 | 常规语法结构 | 示例 |
---|---|---|
#if指令 | #if preprocessor-expression code #endif |
#if CSHARP2PLUS Console.Clear(); #endif |
#elif指令 | #if preprocessor-expression1 code #elif preprocessor-expression2 code #endif |
#if LINUX … #elif WINDOWS … #endif |
#else指令 | #if code #else code #endif |
#if CSHARP1 … #else … #endif |
#define指令 | #define conditional-symbol | #define CSHARP2PLUS |
#undef指令 | #undef conditional-symbol | #undef CSHARP2PlUS |
#error指令 | #error preproc-message | #error Buggy implementation |
#warning指令 | #warning preproc-message | #warning Needs code review |
#pragma指令 | #pragma warning | #pragma warning disable 1030 |
#line指令 | #line org-line new-line | #line 467 “TicTacToe.cs” … |
#line default | #line default | |
#region指令 | #region preproc-message code #endregion |
#region … #endregion |
排除和包含代码
或许最常用的预处理指令就是控制何时以及如何包含代码的指令。
例如,要使代码兼容C#2.0(及以后版本)和C#1.0的编译器,可以使用一个预处理指令指示在遇到1.0编译器时排除C#2.0特有的代码。
|
System.Console.Clear()方法,是CLI2.0或更高版本才支持的方法。是用#if和#endif预处理指令,这行代码只有在定义了预处理符号CSHARP2PLUS的前提下才会编译。
#define指令
#define指令,可以把它看作声明一个变量。具体和代码中声明变量又有如下区别:
- #define指令必须在代码文件中的第一句。
- 没有分号作为结束标记。
- 单独使用是没有任何意义的,但是和#if,#elif,#else,#endif一起使用就截然不同了。
可以采用两种方式定义预处理符号。第一种方式是使用#define指令。
|
第二种方式是在编译时使用define选项。
>csc.exe /define:CSHARP2PLUS TicTacToe.cs |
用Mono编译器实现上面相同的功能。
>mcs.exe -define:CSHARP2PLUS TicTacToe.cs |
多个定义以分号分隔。使用define编译器选项的优点是不需要更改源代码,所以可用相同的源代码文件生成两套不同的二进制程序。
要取消符号定义,可以采用和#define相同的方式来使用#undef指令。
生成错误和警告
可以插入#error和#warning指令来分别生成错误和警告消息。
包含#warning指令后,编译器会主动发出警告。利用警告的信息,可以标记出代码中潜在的Bug和可以改进的部分。它是提醒开发者任务尚未完结的好帮手。
关闭警告信息
警告可以指出代码中可能存在的问题。然而有的警告可以合理地忽略。C#2.0以及之后的编译器提供了预处理指令#pragma来关闭或还原警告。
使用预处理指令#pragma禁用#warning指令
使用预处理指令#pragma还原警告
nowarn:<warn list>选项
除了#pragma指令,C#编译器通常还支持nowarn:<warn list>选项。它可以获得与#pragma相同的效果,只是不用把它加进源代码,而是把它作为编译器选项使用。nowarn选项会影响整个编译过程,而#pragma选项只影响该指令所在的文件。
>csc /doc:generate.xml /nowarn:1591 /out:generate.exe Program.cs |
指定行号
利用#line指令可以改变C#编译器在报告错误或警告时显示的行号。真实行号显示在最左侧。
- 使用#line指令后,编译器会将实际发生在2行的警告报告在113行上发生。
- 在#line指令后添加default,会反转之前所有的#line的效果,并指示编译器报告真实的行号,而不是之前使用#line指定的行号。
可视编辑器提示
C#提供了只有在可视代码编辑器中才有用的两个预处理指令,也就是#region和#endregion。像Microsoft Visual Studio这样的可视代码编辑器能够搜索源代码,找到这些指令,并相应地进行处理。