ONE PIECE ------ C#

  1. C#区分大小写。
  2. 单行注释以两个斜杠字符开头(//) ,多行注释以一条斜杠和一个星号(/*)开头,以一个星号和一条斜杠(*/)结尾。注释是为了让人更好地理解程序,它们并不是程序的一部分。
  3. namespace 关键字声明了应与类相关的名称空间。其后花括号中的所有代码都被认为是在这个名称空间中。
  4. 编译器在using语句指定的名称空间中查找没有在当前名称空间中定义但在代码中引用的类,使用using 指令的原因是:要使用类System.Console。using System 语句允许把这个类简写为Console(System 名称空间中的其他类也与此类似)。如果没有using 语句,就必须完全限定对Console.WriteLine()方法的调用,system.Console.WriteLine("Hello");
  5. C#中做的所有工作都依赖于.NET 基类。
  6. 所有的C#代码都必须包含在一个类中。类的声明包括c1ass 关键字,其后是类名和一对花括号,与类相关的所有代码都应放在这对花括号中。
  7. 声明一个类MyFirstClassOP。假设该类位于OP 名称空间中,其完整的名称是OP.MyFirstClassOP。
  8. 每个C#可执行文件(如控制台应用程序、Windows 应用程序和Windows服务)都必须有一个入口点——Main()方法(注意M大写)。在程序启动时会调用这个方法。该方法要么没有返回值(void),要么返回一个整数(int)。
  9. 在 C#中声明变量:datatype identifier;声明之后,就可以使用赋值运算符(=)给它赋值。
    int i;
    i = 8;
    string s = "LY";
  10. 编译器不允许在表达式中使用未初始化的变量。编译器需要用某个初始值对变量进行初始化,之后才能在操作中引用该变量。大多数现代编译器把没有初始化标记为警告,但C#编译器把它当作错误来看待。
  11. 如果在一条语句中声明和初始化了多个变量,那么所有的变量都具有相同的数据类型:
    int x = 10, y = 20;
  12. 要声明不同类型的变量,需要使用单独的语句。在多个变量的声明中,不能指定不同的数据类型:
    int x = 10;
    bool y = true;
    int x = 10, bool y = true;
  13. 在C#中实例化一个引用对象需要使用new 关键字
  14. 类型推断(type inference)使用var 关键字。编译器可以根据变量的初始化值“推断”变量的类型。例如:
    int someNumber = 0;
    就变成:
    var someNumber = 0;
    即使someNumber 从来没有声明为int,编译器也可以确定,只要someNumber 在其作用域内,就是一个int。编译后,上面两个语句是等价的。
    声明了变量,推断出了类型后,就不能改变变量类型了。变量的类型确定后,就遵循其他变量类型遵循的强类型化规则。
  15. 变量的作用域是可以访问该变量的代码区域。一般情况下,确定作用域遵循以下规则:
    只要类在某个作用域内,其字段(也称为成员变量)也在该作用域内。
    a.局部变量存在于表示声明该变量的块语句或方法结束的右花括号之前的作用域内。
    b.在 for、while 或类似语句中声明的局部变量存在于该循环体内。
  16. 同名的局部变量不能在同一作用域内声明两次
  17. 常量是其值在使用过程中不会发生变化的变量。在声明和初始化变量时,在变量的前面加上关键字const,就可以把该变量指定为一个常量:
    const int a = 100;
    常量具有如下特点:
    a.常量必须在声明时初始化。指定了其值后,就不能再改写了。
    b.常量的值必须能在编译时用于计算。因此,不能用从一个变量中提取的值来初始化常量。如需要这么做,应用只读字段。
    c.常量总是静态的。但注意,不必(实际上,是不允许)在常量声明中包含修饰符static。
  18. C#把数据类型分为两种:值类型和引用类型
    区别是值类型直接存储其值,而引用类型存储对值的引用。这两种类型存储在内存的不同地方:值类型存储在堆栈中,而引用类型存储在托管堆上。注意区分某个类型是值类型还是引用类型,因为这种存储位置的不同会有不同的影响。
  19. 如果变量是一个引用类型,就可以把其值设置为null,表示它不引用任何对象:
    y = null;
    如果将引用类型设置为null,显然就不可能对它调用任何非静态的成员函数或字段,这么做会在运行期间抛出一个异常。
  20. 我们自己声明的类都是引用类型
  21. 如果要把自己的类型定义为值类型,就应把它声明为一个结构。
  22. C#中数据类型都以与平台无关的方式定义。
  23. C#认可的基本预定义类型并没有内置于C#语言中,而是内置于.NET Framework中。
  24. C#有15 个预定义类型,其中13 个是值类型,两个是引用类型(string 和object)。
  25. 整型(值类型):C#支持8 个预定义整数类型,所有整数类型的变量都能被赋予十进制或十六进制的值,后者需要0x 前缀
    如果对一个整数是int、uint、long 或是ulong 没有任何显式的声明,则该变量默认为int 类型。
    为了把输入的值指定为其他整数类型,可以在数字后面加上如下字符:
    uint ui = 1234U;
    1ong l = 1234L;
    ulong ul = 1234UL;
    也可以使用小写字母u 和l,但后者会与整数1 混淆。
    ONE PIECE ------ C#
  26. 浮点类型(值类型):如果在代码中没有对某个非整数值(如12.3)硬编码,则编译器一般假定该变量是double。如果想指定该值为float,可以在其后加上字符F(或f):
    float f = 12.3F;
    ONE PIECE ------ C#
  27. decima类型(值类型):decimal 类型表示精度更高的浮点数,C#一个重要的优点是提供了一种专用类型进行财务计算,这就是decimal 类型,注意,decimal 类型不是基本类型,所以在计算时使用该类型会有性能损失。要把数字指定为decimal 类型,而不是double、float 或整型,可以在数字的后面加上字符M(或m),如下所示。
    decimal d = 12.30M;
    ONE PIECE ------ C#
  28. bool类型(值类型):包含布尔值true 或false,bool 值和整数值不能相互隐式转换。如果变量(或函数的返回类型)声明为bool 类型,就只能使用值true 或false。如果试图使用0 表示false,非0 值表示true,就会出错。
    ONE PIECE ------ C#
  29. 字符类型(值类型):为了保存单个字符的值,C#支持char 数据类型。char 类型的字面量是用单引号括起来的,如'A'。如果把字符放在双引号中,编译器会把它看作字符串,从而产生错误。
    除了把char 表示为字符字面量之外,还可以用4 位十六进制的Unicode 值(如'\u0041')、带有数据类型转换的整数值(如(chaar)65)或十六进制数('\x0041')表示它们。
    ONE PIECE ------ C#
  30. object类型(引用类型):在C#中,object 类型就是最终的父类型,所有内置类型和用户定义的类型都从它派生而来。
    object 类型就可以用于两个目的:
    a. 可以使用object 引用绑定任何子类型的对象。例如,使用object 类型把堆栈中的一个值对象装箱,再移动到堆中。object 引用也可以用于反射,此时必须有代码来处理类型未知的对象。
    b. object 类型执行许多一般用途的基本方法,包括Equals()、GetHashCode()、GetTypc()和ToString()。用户定义的类需要使用一种面向对象技术——重写,提供其中一些方法的替代执行代码。例如,重写ToString()时,要给类提供一个方法,给出类本身的字符串表示。如果类中没有提供这些方法的实现代码,编译器就会使用object 类型中的实现代码,它们在类中的执行不一定正确。
  31. string类型(引用类型):C#有string 关键字,在编译为.NET 类时,它就是System.String。有了它,像字符串连接和字符串复制这样的操作就很简单了:
    string str1 = "Hello ";
    string str2 = "World";
    string str3 = str1 + str2;
    尽管这是一个值类型的赋值,但string 是一个引用类型。string 对象被分配在堆上,而不是栈上。因此,当把一个字符串变量赋予另一个字符串时,会得到对内存中同一个字符串的两个引用。但是,string 与引用类型在常见的操作上有一些区别。例如,字符串是不可改变的。修改其中一个字符串,就会创建一个全新的string 对象,而另一个字符串不发生任何变化。(这实际上是运算符重载的结果)
    字符串字面量放在双引号中("…");如果试图把字符串放在单引号中,编译器就会把它当作char,从而引发错误。C#字符串和char 一样,可以包含Unicode 和十六进制数转义序列。因为这些转义序列以一个反斜杠开头,所以不能在字符串中使用这个非转义的反斜杠字符,而需要用两个反斜杠字符(\\)来表示它:
    string filepath = "C:\\A\\b.cs";
    即使用户相信自己可以在任何情况下都记住要这么做,但输入两个反斜杠字符会令人迷惑。幸好,C#提供了另一种替代方式。可以在字符串字面量的前面加上字符@,在这个字符后的所有字符都看作是其原来的含义——它们不会解释为转义字符:
    string filepath = @"C:\A\b.cs";
    甚至允许在字符串字面量中包含换行符:
    string strAB= @"'A
    b.";
  32. 转义字符
    ONE PIECE ------ C#
  33. if语句:测试特定条件是否满足
    if (condition)
       statement(s)
    e1se
       statement(s)
    如果在条件中要执行多个语句,就需要用花括号({…})把这些语句组合为一个块。可以单独使用if 语句,不加最后的else 语句。也可以合并else if 子句,测试多个条件。
    对于if,要注意的一点是如果条件分支中只有一条语句,就无需使用花括号。
    在C#中,if 子句中的表达式必须等于布尔值。
    特别注意,C#使用“==”对变量进行等于比较。此时不要使用“=”,一个“=”用于赋值。
  34. switch语句:适合于从一组互斥的分支中选择一个执行分支。其形式是switch 参数的后面跟一组case 子句。如果switch 参数中表达式的值等于某个case 子句旁边的某个值,就执行该case 子句中的代码。此时不需要使用花括号把语句组合到块中;只需使用break 语句标记每段case 代码的结尾即可。也可以在switch 语句中包含一条default 子句,如果表达式不等于任何case 子句的值,就执行default 子句的代码。如果**了块中靠前的一条case 子句,后面的case 子句就不会被**。
    switch (integerA)
    {
       case 1:
          Conso1e.WriteLine("integerA =1");
          break;
       case 2:
          Console.WriteLine("integerA =2");
          break;
       case 3:
          Console.WriteLine("integerA =3");
          break;
       default:
          Console.WriteLine("integerA is not 1, 2, or 3");
          break;
    }
    注意case 的值必须是常量表达式;不允许使用变量。
    如果一条case 子句为空,就可以从这个case 跳到下一条case 上,这样就可以用相同的方式处理两条或多条case 子句了(不需要goto 语句)。
    switch(country)
    {
       case "au":
       case "uk":
       case "us":
          language = "Eng1ish";
          break;
       case "at":
       case "de":
          1anguage = "German";
          break;
    }
    在C#中,switch 语句的一个有趣的地方是case 子句的排放顺序是无关紧要的,甚至可以把default子句放在最前面!因此,任何两条case 都不能相同。这包括值相同的不同常量。
  35. for循环:C#的for 循环提供的迭代循环机制是在执行下一次迭代前,测试是否满足某个条件,其语法如下:
    for (initializer; condition; iterator)
       statement(s)
    其中:
    a. initializer 是指在执行第一次循环前要计算的表达式(通常把一个局部变量初始化为循环计
    数器);
    b. condition 是在每次迭代执行新循环前要测试的表达式(它必须等于true,才能执行下一次迭代);
    c. iterator 是每次迭代完要计算的表达式(通常是递增循环计数器)。
    当condition 等于false 时,迭代停止。
    for 循环是所谓的预测试循环,因为循环条件是在执行循环语句前计算的,如果循环条件为假,循环语句就根本不会执行。
    for 循环非常适合于一个语句或语句块重复执行预定的次数。
  36. while循环:与 for 循环一样,while 也是一个预测试循环。其语法是类似的,但while 循环只有一个表达式:
    while(condition)
       statement(s);
    与for 循环不同的是,while 循环最常用于以下情况:在循环开始前,不知道重复执行一个语句或语句块的次数。通常,在某次迭代中,while 循环体中的语句把布尔标志设置为false,结束循环。
  37. do...while循环:do...while 循环是while 循环的后测试版本。该循环的测试条件要在执行完循环体之后执行。因此do...while 循环适用于至少要将循环体执行一次的情况:
    do
    {
       ……
    } while (condition);
  38. foreach循环:foreach 循环可以迭代集合中的每一项。集合是一种包含一系列对象的对象即可。从技术上看,要使用集合对象,就必须支持IEnumerable接口。集合的例子有C#数组、System.Collection 名称空间中的集合类,以及用户定义的集合类。从下面的代码中可以了解foreach 循环的语法,其中假定arrayOfInts 是一个整型数组:
    foreach (int temp in arrayofInts)
    {
       Console.WriteLine(temp);
    }
    其中,foreach 循环每次迭代数组中的一个元素。它把每个元素的值放在int 型的变量temp 中,然后执行一次循环迭代。
    这里也可以使用类型推断功能。此时,foreach 循环变成:
    foreach (var temp in arrayOfInts)
    ...
    注意,foreach 循环不能改变集合中各项(上面的temp)的值,所以下面的代码不会编译:
    foreach (int temp in arrayOfInts)
    {
       temp++;
       Console.WriteLine(temp);
    }
    如果需要迭代集合中的各项,并改变它们的值,就应使用for 循环。
  39. goto语句:goto 语句可以直接跳转到程序中用标签指定的另一行(标签是一个标识符,后跟一个冒号):
    goto Label1;
    Console.WriteLine("This won't be executed");
    Label1:
    Console.WriteLine("Continuing execution from here");
    goto 语句有两个限制。不能跳转到像for 循环这样的代码块中,也不能跳出类的范围,不能退出try...catch 块后面的finally。
  40. break语句:在switch 语句中使用它退出某个case 语句。实际上,break 也可以用于退出for、foreach、while 或do...while 循环,该语句会使控制流执行循环后面的语句。如果该语句放在嵌套的循环中,就执行最内部循环后面的语句。如果break放在switch 语句或循环外部,就会产生编译错误。
  41. continue语句:continue 语句类似于break,也必须在for、foreach、while 或do...while 循环中使用。但它只退出循环的当前迭代,开始执行循环的下一次迭代,而不是退出循环。
  42. return语句:return 语句用于退出类的方法,把控制权返回方法的调用者。如果方法有返回类型,return 语句必须返回这个类型的值;如果方法返回void,应使用没有表达式的return 语句。
  43. 枚举:枚举是用户定义的整数类型。在声明一个枚举时,要指定该枚举的实例可以包含的一组可接受的值。不仅如此,还可以给值指定易于记忆的名称。如果在代码的某个地方,要试图把一个不在可接受范围内的值赋予枚举的一个实例,编译器就会报告一个错误。
    可以定义如下的枚举:
    public enum TimeOfDay
    {
       Morning = 0,
       Afternoon = 1,
       Evening = 2
    }
    在C#中,枚举的真正强大之处是它们在后台会实例化为派生于基类System.Enum 的结构。这表示可以对它们调用方法,执行有用的任务。注意因为.NET FrameWork 的执行方式,在语法上把枚举当做结构是不会造成性能损失。实际上,一旦代码编译好,枚举就成为基本类型,与int 和float类似。
    可以获取枚举的字符串表示,例如使用前面的TimeOfDay 枚举:
    TimeOfDay time = TimeOfDay.Afternoon;
    Conso1e.WriteLine(time.ToString());//会返回字符串Afternoon。
    另外,还可以从字符串中获取枚举值:
    TimeOfDay time2 = (TimeOfDay) Enum.Parse(typeof(TimeOfDay), "afternoon", true);
    Console.WriteLine((int)time2);
    这段代码说明了如何从字符串获取枚举值,并转换为整数。要从字符串中转换,需要使用静态的Enum.Parse()方法,这个方法带3 个参数。第1 个参数是要使用的枚举类型,其语法是关键字typeof后跟放在括号中的枚举类名。第2 个参数是要转换的字符串,第3 个参数是一个bool,指定在进行转换时是否忽略大小写。最后,注意Enum.Parse()方法实际上返回一个对象引用——我们需要把这个字符串显式转换为需要的枚举类型(这是一个拆箱操作的例子)。对于上面的代码,将返回1,作为一个对象,对应于TimeOfDay.Afternoon 的枚举值。在显式转换为int 时,会再次生成1。
  44. 名称空间:名称空间提供了一种组织相关类和其他类型的方式。与文件或组件不同,名称空间是一种逻辑组合,而不是物理组合。把一个类型放在名称空间中,可以有效地给这个类型指定一个较长的名称,该名称包括类型的名称空间,名称之间用句点分隔开,最后是类名。名称空间与程序集无关。同一个程序集中可以有不同的名称空间,也可以在不同的程序集中定义同一个名称空间中的类型。
  45. using语句:C#允许简写类的全名。为此,要在文件的顶部列出类的名称空间,前面加上using 关键字。在文件的其他地方,就可以使用其类型名称来引用名称空间中的类型了:
    using System;
    几乎所有的C#源代码都以语句using System;开头,这仅是因为Microsoft 提供的许多有用的类都包含在System 名称空间中。
    using 关键字的另一个用途是给类和名称空间指定别名。其语法如下:
    using alias = NamespaceName;
    注意名称空间别名的修饰符是“::”。
  46. Main()方法:C#是从方法Main()开始执行的。这个方法必须是类或结构的静态方法,并且其返回类型必须是int 或void。虽然显式指定public 修饰符是很常见的,因为按照定义,必须在程序外部调用该方法,但我们给该入口点方法指定什么访问级别并不重要,即使把该方法标记为private,它也可以运行。
    在编译C#控制台或Windows 应用程序时,默认情况下,编译器会在类中查找与上述签名匹配的Main()方法,并使这个类方法成为程序的入口点。如果有多个Main()方法,编译器就会返回一个错误消息。
    给Main()方法传递参数,可以让CLR 包含一个参数,这个参数是一个字符串数组,传统上称为args(但C#可以接受任何名称)。在启动程序时,程序可以使用这个数组。
  47. XML格式的文档说明:根据特定的注释自动创建XML格式的文档说明。这些注释都是单行注释,但都以3条斜杠(///)开头,而不是通常的两条斜杠。在这些注释中,可以把包含类型和类型成员的文档说明的XML 标记放在代码中。
  48. C#预处理器指令:这些命令从来不会转化为可执行代码中的命令,但会影响编译过程的各个方面。例如,使用预处理器指令可以禁止编译器编译代码的某一部分。
    预处理器指令的开头都有符号#。
    #define和#undef:
    #define 的用法如下所示:
    #define DEBUG
    它告诉编译器存在给定名称的符号,在本例中是DEBUG。这有点类似于声明一个变量,但这个变量并没有真正的值,只是存在而己。这个符号不是实际代码的一部分,而只在编译器编译代码时存在。在C#代码中它没有任何意义。
    #undef 正好相反——它删除符号的定义:
    #undef DEBUG
    如果符号不存在,#undef 就没有任何作用。同样,如果符号已经存在,则#define 也不起作用。必须把#define 和#undef 命令放在C#源文件的开头位置,在声明要编译的任何对象的代码之前。
    #if, #elif, #else和#endif:这些指令告诉编译器是否要编译某个代码块。
    int DoSomeWork(double x)
    {
    // do something
    #if DEBUG
    Console.WriteLine("x is " + x);
    #endif
    }
    这段代码会像往常那样编译,但Console.WriteLine()命令包含在#if 子句内。这行代码只有在前面的#define 命令定义了符号DEBUG 后才执行。当编译器遇到#if 语句后,将先检查相关的符号是否存在,如果符号存在,就编译#if 子句中的代码。否则,编译器会忽略所有的代码,直到遇到匹配的#endif 指令为止。#if 和#elif 还支持一组逻辑运算符“!”、“==”、“!=”和“||”。如果符号存在,就被认为是true,否则为false。
    #warning和#error:当编译器遇到它们时,会分别产生警告或错误。如果编译器遇到#warning 指令,会给用户显示#warning指令后面的文本,之后编译继续进行。如果编译器遇到#error 指令,就会给用户显示后面的文本,作为一条编译错误消息,然后会立即退出编译,不会生成IL 代码。
    #region和#endregion:#region 和#endregion 指令用于把一段代码标记为有给定名称的一个块。
    #line:#line 指令可以用于改变编译器在警告和错误信息中显示的文件名和行号信息。
    #pragma:#pragma 指令可以抑制或还原指定的编译警告。与命令行选项不同,#pragma 指令可以在类或方法级别执行,对抑制警告的内容和抑制的时间进行更精细的控制。
  49. 标识符:标识符是给变量、用户定义的类型(如类和结构)和这些类型的成员指定的名称。标识符区分大小写,所以interestRate 和InterestRate 是不同的变量。确定在C#中可以使用什么标识符有两条规则:
    a. 尽管可以包含数字字符,但它们必须以字母或下划线开头。
    b. 不能把C#关键字用作标识符。
    如果需要把某一保留字用作标识符(例如,访问一个用另一种语言编写的类),那么可以在标识符的前面加上前缀符号@,告知编译器其后的内容是一个标识符,而不是C#关键字(所以abstract 不是有效的标识符,@abstract 才是)。最后,标识符也可以包含Unicode 字符,用语法\uXXXX 来指定,其中XXXX 是Unicode 字符的4 位十六进制编码。
  50. 关键字
    ONE PIECE ------ C#
  51. Hungarian 表示法:变量名用带有前缀字母来表示某种数据类型,这种约定称为Hungarian 表示法。这样,其他阅读该代码的开发人员就可以立即从变量名中了解它代表什么数据类型。
  52. Pascal 表示法:在许多情况下,名称都应使用Pascal 大小写形式。Pascal 大小写形式指名称中单词的首字母大写,如EmployeeSalary、ConfirmationDialog、PlainTextEncoding。注意,名称空间和类,以及基类中的成员等的名称都应遵循该规则,最好不要使用带有下划线字符的单词,即名称不应是employee_salary。
  53. camel 表示法:这种形式类似于Pascal 大小写形式,但名称中第一个单词的首字母不大写,如employeeSalary、confirmationDialog、plainTextEncoding。
    有3 种情况可以使用camel 大小写形式。
    a. 类型中所有私有成员字段的名称都应是camel 大小写形式
    b. 传递给方法的所有参数的名称都应是camel 大小写形式
    c. camel 大小写形式也可以用于区分同名的两个对象——比较常见的情况是属性封装一个字段:
    private string employeeName;
    public string EmployeeName
    {
    get
    {
    return employeeName;
    }
    }
    如果这么做,则私有成员总是使用camel 大小写形式,而公有的或受保护的成员总是使用Pascal
    大小写形式,这样使用这段代码的其他类就只能使用Pascal 大小写形式的名称了(除了参数名以外)。
  54. ……