The key of C# 学习笔记I-II

作者 :Kemin's booootLog  http://blog.csdn.net/keminlau/

Sunday, October 3, 2004

    1. 微软提出的CLS(Common Language Specification, 通用语言标准)对能被用来编写dotNET程序的语言的最小功能集做出了规定。
    2. 就拿C#来说,它是目前程序设计语言“以效率换安全”发展潮流的一个产物。
    3. “编译器”把整个程序一次性地全部转换为将被计算机执行的机器代码;机器码形成一个“可执行文件”,这个文件可以直接在计算机上运行。但因为机器码是与某特定计算机相关联,所以可执行文件只能在特定的类型的计算机上执行。
    4. 传统过程化程序设计语言(如C),数据将由过程(或者叫“函数”“子例程”)代码进行处理;在面向对象程序设计语言里,程序员创建各种“类”,并由此衍生出“对象”,一个对象就是代码和数据的混合体,数据由对象自身进行处理。这种观念大大提高了代码的“复用性”。
    5. 20世纪90年代,SUN公司推出了Java,这种面向对象程序设计语言以C为蓝本,但与C++有着显著的区别。JAVA摒弃了C++某些难看又难用的语法,也剔除了某些有危险性的C语言功能,但它保留了C语言简洁紧凑的特点。
    6. 一个“操作符”(Operater)就是一个将使计算机执行某一个特定操作的符号或者单词;
    7. 在C#及其他很多现代程序设计语言里,程序代码都必须写成称为“类”和“方法”的单元。
    8. 最简单的C#程序仅包含一个类,这个类又仅包含一个方法---》Main()入口函数。
    9. 一个方法声明将由一个修饰符(such as static),一个返回值类型(such as void),一个方法名称,一个括在一对圆括号的输入参数列表,一个包含着该方法代码主体的语句块等组成.
    10. 一个方法就是一组用来完成某项特定任务的程序代码.
    11. 一个表达式可以是一个变量、一个常量或者是一个操作的执行或计算结果。
    12. 当C#对两个整数做除法运算时,它会把结果“截短”。幸好有求余(%)弥补。

Tuesday, October 5,2004

  1. 表达式(expression)是由操作数(operand)和操作符(operater)构成。一个表达式有他的值,因此表达式可以作另一个表达式的操作数。
  2. C家族重要特征之一,精练,少打字。“复合赋值”操作符:+=加等;-+减等;++递增;--递减;……
  3. C#编译器的特殊功能:出现在类、方法或者其他程序结构元素的前面且以三个斜线“///”开头的注释允许包含XML标记。C#编译器将生成一个XML文件来存放这些标记。
  4. 在如今的数字计算机里,各种信息都将编码为一系列“比特”;比特是信息最简单的表示形式。计算机硬件用电压的高低或者有无来表示一比特;
  5. 现今的个人电脑大都是32位计算机,这是因为它们以32比特作为对数据进行存储和处理的基本单位。早期的计算机每次只能处理8个比特,人们把8个比特称为一个字节。即使到了今天,字节仍是计算机领域最常用计量单位。
  6. C#使用32比特(4个字节)来表示一个int类型的变量。一个int可以用来存储正数和负数,所以int正式定义是“32比特的带符号整数”。
  7. 二进制数是以2的幂次来表示的,2的N次幂就是一个二进制数字1后面跟上N个0所构成的一个二进制数。如:1-0000-0000等于256或28
  8. 现代的数字计算机里,负数通常被表示成“二进制补码”。二进制补码指的是一种用来对正数和负数进行转换的方法。如要表示-7(假设只有4个比特,头一位为符号位):先得7的二进制表示:0111,再把0111按取反加一得“补码”1001,1001即-7
  9. C#关键字checked and unchecked激活溢出检查机制
  10. C#支持8种整型数据;选用整型数据的基本原则:
    @97%优先考虑使用int类型,32位便于处理也更有效率
    @数值比int大,才选用long
    @如果需要使用磁盘文件来存储或检索大量小整数,考虑选用shot,byte 节约空间
  11. 字段和方法的相似之处是它们都是某个类或者某个结构的成员,但字段要简单得多。一个字段其实就是一个变量或者一个取值固定不变的常数。

 

Thursday, October 7, 2004

  1. 在一条涉及多种运算的复杂语句里,C#将根据操作符的优先级和运算规则依次对各有关操作的操作数进行必要的类型转换(小容量向大容量转)。在赋值操作中,等号右边的表达式将被隐含地转换为等左边的变量的类型。
  2. 方法重载(overload)就是一个方法的多种不同版本。如Console.WriteLine()方法的方法签名(即输入参数)可以是整数也可以是字符串。
  3. 同样,操作符重载是指用同一个操作符完成不同类型的操作的做法。如加号“+”用作数值加法和字符串合并。
  4. C#里的“字符串里的引号”问题:
    1. 用转义字符改变字符的正常含义如:string StringWithQuotes = "The name of the composition is/"Appalachian Spring./"";
    2. 用"@"关提掉转义如: string Directory = @"C:/Program files/Key of c#";
  5. 程序在内存中分布(清楚存放部位)
    1. 代码区:存放程序的代码,程序的各个函数代码块;
    2. 全局数据区:存放程序的全局数据和静态数据;
    3. 堆区:存放程序的动态数据;
    4. 栈区:存放程序的局部数据,可以说是函数中的数据;
    5. 特别的是栈区的数据,函数结束就会释放.
  6. C#里的“引用”不是C/C++里的“指针”,它是安全的“引用指针”,与C/C++“指针”完成类似的操作。引用类型数据(如类)的具体数据内容被保存在从里分配的某个内存块中,而这个内存块的引用指针则保存在堆栈上。
  7. 从内存分配来理解null空串的区别:
    1. 保留字null是一个取值为0的引用指针,这意味着C#不会多堆里分配内存。一个没用引用任何堆内存的字符串变量叫作一个“null字符串”。
    2. 当某个字符串变量被赋值为null时,C#不会从堆里为它分配任何内存且堆栈上与它对应的值是0;
    3. 当某个字符串变量等于空字符串时,C#会从堆里为它分配一些内存,但字符串长度为0
  8. 文本是人与计算机进行交流的主要媒介。人们“强迫”计算机显示文本输出和接受文本输入。即便是在只显示数值的场合,计算机也必须把各有关的有关数值的二进制表示形式转换为相应的文本输出形式。
  9. int与string互转:
    1. ToString是一个实例(instance)方法: string str = 123.ToString();//存在实例
    2. Int32.Parse是一个静态(static)方法: int i = Int32.Parse("123");//创建实例
  10. System名字空间还有一个很好用的Convert类。程序员可以利用Convert类所提供的各种静态方法对任意两种数据类型进行类型转换。如:
    int i = Convert.ToInt32(str);
    string str = Convert.ToString(i);
  11. C#两种非整形数据类型:浮点数decimal
    1. 浮点数很常用,但有着一个先天的不足,就是精度不够(float七位有效数字,double有15或16位)
    2. 对比于int和uint(32位),long和ulong(64位),decimal使用128位16个字节储存数据;其中用96位表示有效数字(29个),5位表小数点位置(0-28),一位作符号位,共102位余26位。

Saturday, October 9, 2004

  1. decimal舍入
    1. “四舍五入”:
      Decimal.Truncate(Value);//向零方向舍入
      Decimal.Floor(Value);//向负无穷方向舍入
    2. “舍入为偶数”:
      Decimal.Round(Value,Digits);//Round(3.345,2) = 3.34
  2. 格式字符串
    Consloe.WriteLine("{0,20:X5}{1,10:C2}",str1,str2);//{占位,输出宽度:格式}
  3. 保留字“static”表明该方法为静态方法,将作用于类或结构而不是作用于类或结构中的某个特定的方法,它必须与类或结构的名字配合使用,如Console.WriteLine();
  4. 字段就是在一个类的内部,但在这个类里的所有方法的外部所声明的变量或者常数。如里字段只与这个类关联而不与类的实例关联,声明为静态static。
  5. new保留字的角色和作用:
    new表达式的返回值是一个引用(指针),它指系统从堆分配的那个内存块。如:int[] aiArray = new int[]
  6. 进一步理解new的作用:明确给对象在堆里分配空间
    1. Random rand;//rand没被初始化,什么都不做
    2. rand = new Random();//为rand从堆分配内存和初始化操作等
  7. C#不允许你用保留字const去声明一个数组——只有在编译阶段被确定或计算出来的值才能被声明为常数;数组需要一个new操作,而new操作只有等到运行阶段才会发生。
  8. 程序学一项基本原则——“把变量,不管是数组还是其它类型的变量,尽可能声明为局部变量”;可是当需要在一个程序里频繁调用某个方法而这个方法又要用到一个其元素都是些常数的数组时,就应该把那个数组搬到那个方法的外部并把它声明为一个static字段。
  9. .NET的Random类供程序员用来从从那颗随机种子开始生成随机数。

Monday, October 11, 2004

  1. 逻辑公式--德·莫干定律:
    1. !( A | B ) = !A & !B 
    2. !( A & B ) = !A | !B
  2. C#中的char数据类型:代表单个字符
    在C#里,可以用一个字符array去创建一个字符串,也可以把一个字符串转换为一个字符array,但把一个C#字符串说成是一个字符array是不恰当的。C#有字符串数据类型string。
  3. 所有的程序设计语言都是用数值来代表字符的,但C语言把char看作是一种与int,short和long没有什么不同的数值类型。在C里,char的宽度是8个比特且代表一个ASCII字符,但在C#里,char的宽度是16个比特且代表的是一个Unicode字符。C#里的char变量不是数值。
  4. String.Chars 属性
    在 C# 中,该属性为 String 类的索引器。获取此实例中位于指定字符位置的字符。
  5. new构造器的理解
    如果要你创建一个由21个"@"字符构成的字符串,你会怎么做?
    string str = "@@@@@@@@@@@@@@@@@@@@@";//老实型
    string str = new string('@', 21);//简单聪明




Wednesday, October 13, 2004

  1. 浮点数的比较运算
    1. 对浮点数进行比较,必须先舍入为相同精度再进行,因其的不精确性。
    2. 在需要测试某个float值或double值是否为无穷大或NaN时,不能直接用Single或Double结构中的PositiveInfinity、NegativeInfinity或NaN字段进行比较;应选用IsInfinity等方法来完成,因其有二义。
  2. 建议最好不要用“==”操作符去比较两个布尔值,因为不小心少打一个等号,会致命的。可以使用异或操作符“^”将更稳妥。异或操作等价于“!=”操作符,所以有不少人把“^”称为逻辑“不等于”操作符。只要用“^”操作符对“!=”操作的结果再进行一次逻辑非处理,就能得到与“==”操作符同样的效果,如:
    1. bWeAreCompatible = bYouLikeMahler == bILikeMahler
    2. bWeAreCompatible = !(bYouLikeMahler ^ bILikeMahler)
  3. 局部变量只在对它做出了声明的那个{语句块}里才是可见的。这个语句块有多大,求证中....
  4. C#没有“else语句”之类的东东,C#中的if语句由一个if部分和一个可选的else部分构成。C#也没有“else if语句”,是两条if组合在一起而矣。
  5. 条件操作符
    1. 条件与(&&)与条件或(||)
      1. bExpression1 && bExpression2//如果bExpression1被求值为false,bExpression2将不会被求值
      2. bExpression1 || bExpression2//如果bExpression1被求值为true,bExpression2将不会被求值
    2. 古怪“条件表达式”(?:),唯一三目操作符。
  6.     一、C#的异常处理所用到关键字

    1.      try 用于检查发生的异常,并帮助发送任何可能的异常。

    2.      catch 以控制权更大的方式处理错误,可以有多个catch子句。

    3.      finally 无论是否引发了异常,finally的代码块都将被执行。

    1.      throw 用于引发异常,可引发预定义异常和自定义异常。
  7.     二、C#异常处理的格式

    以下是引用片段:
    try
    {
      程序代码块;
    }
    catch(Exception e)
    {
       异常处理代码块;
    }
    finally
    {
       无论是否发生异常,均要执行的代码块;
    }

  8. 有效的调试技巧
    没有漏网的鱼 "This statement should never be executed."

  9. for语句以保留字"for"开始,后面跟着一对圆括号,括号里有三个用分号隔开的表达式。注意,这是分号在C#中惟一不被当作一个语句分隔符来对待的地方!这三个表达式分别叫作for循环的“初始化表达式”、“循环条件表达式”和“步长表达式”。


 

Friday, October 15, 2004

  1. 算法“Sieve of Eratosthences”(Eratosthences之筛)是一种用来生成素数的算法。素数是只能被1和它本身整除的整数。2是第一个素数,也是素数中惟一的一个偶数。
  2. CPU耗时比较:方法调用 > 乘除运算 > 加减运算
  3. switch语句
    在Java中,switch语句只能处理整数。但C#中的switch语句不同,它还能够处理字符变量。

    switch (args[0]) {
        case "老板":
            Console.WriteLine("早上好!我们随时准备为您效劳!");
            break;
        case "雇员":
            Console.WriteLine("早上好!你可以开始工作了!");
            break;
        default:
            Console.WriteLine("早上好!祝你好运!");
            break;
    }


  4. 与Java中的switch不同,C#的switch语句要求每一个case块或者在块的末尾提供一个break语句,或者用goto转到switch内的其他case标签。这就是所谓C#的“不允许留下swicth分支漏斗”的规定,不过你可以让一个switch分支有多个switch标号。如:

    ....
    case "*"://多种乘法运算符
    case "x"://
    case "X"://
        dResult = dNum1 * dNum2
        break;
    ....

  5. 编写C#程序的“基本工具”:
    1. 声明语句;
    2. 赋值语句;
    3. 选择语句(if, switch);//它们使程序能够根据一个比较操作或者其他布尔操作的结果有选择地改变执行路线
    4. 循环语句(while, do, for, foreach);//它们使程序能够反复多次地执行同一组语句。
    5. 跳转语句(return, break, continue, throw, goto);//它们使程序能够从一个地方跳转到另一个地方去继续执行。
  6. C#没有>>>移位操作符
    C#支持uint和ulong之类的无符号变量类型。因此,在C#中,右移操作符(即“>>”)对于无符号变量类型和带符号变量类型(比如int和long)的处理方式不同。右移uint和ulong丢弃低位并把空出的高位设置为零;但对于int和long类型的变量,“>>”操作符丢弃低位,同时,只有当变量值是正数时,“>>”才把空出的高位设置成零;如果“>>”操作的是一个负数,空出的高位被设置成为1。

    Java中不存在无符号的变量类型。因此,我们用“>>>”操作符在右移时引入负号位;否则,使用“>>”操作符。
  7. 枚举器
    枚举器即enum类型(Enumerator,或称为计数器),它是一个相关常量的集合。精确地说,enum类型声明为一组相关的符号常量定义了一个类型名字。例如,你可以创建一个名为Fruit(水果)的枚举器,把它作为一个变量值的类型使用,从而把变量可能的取值范围限制为枚举器中出现的值。
    public class Demo {
      public enum Fruit {
            Apple, Banana, Cherry, Durian
      }
      public void Process(Fruit fruit) {
        switch (fruit) {
            case Fruit.Apple:
                ...
                break;
            case Fruit.Banana:
                ...
                break;
            case Fruit.Cherry:
                ...
                break;
            case Fruit.Durian:
                ...
                break;
        }
      }
    }

 

 

Sunday, October 17, 2004

  1. C#方法调用传递的参数分四类:
    1. 默认的值参数(value parameter); //传递复制品
    2. 引用参数(reference parameter),关键字"ref";//传递引用指针
    3. 输出参数(output parameter),关键字"out"。//方法返回一个以上的返回值时使用
    4. 数组参数(array parameter),关键字"params"
  2. 引用参数输出参数的区别:
    “引用参数”与“输出参数”非常相似。out修饰符ref修饰符有很相似的地方:传址。事实上保留字“ref”和“out”本身在中间语言里的实现是一模一样的。但C#中的ref参数与out参数还是有区别的:
    1. ref参数必须在进入方法之前得到赋值;
    2. out参数则必须在离开方法之前得到赋值。需要记住输出参数与通常的函数返回值有一定的区别:函数返回值往往存在堆栈里,在返回时弹出;而输出参数需要用户预先制定存储位置,也就是用户需要提前声明变量--当然也可以初始化。

      using System;
      class Test    //拆分姓名
      {
          static void ResoluteName(string fullname,out string firstname,out string lastname)
          {
              string[] strArray=fullname.Split(new char[]{' '});
              firstname=strArray[0];
              lastname=strArray[1];
          }
          public static void Main()
          {
               
                      //string MyName="Cornfield Lee";
                      Console.WriteLine("Enter Your Name:");
                      string MyName = Console.ReadLine();
              string MyFirstName,MyLastName;

              ResoluteName(MyName,out MyFirstName,out MyLastName);

              Console.WriteLine("My first name: {0}, My last name: {1}",
                      MyFirstName, MyLastName);
          }
      }

  3. 数组参数(关键字"params")
    using System;
    class Test    //合计所有整数值
    {
        static int Sum(params int[] args)
        {
            int s=0;
            foreach(int n in args)
            {
                s+=n;
            }
            return s;
        }
        static void Main()
        {
            int[] var=new int[]{1,2,3,4,5};
            Console.WriteLine("The Sum:"+Sum(var));//传数组变量
            Console.WriteLine("The Sum:"+Sum(10,20,30,40,50));//传能够隐式转化为数组的参数
        }
    }

    注意以下两个规定:
    1. 数组参数只能是一维的;
    2. 如果有多个输入参数,就只允许一个输入参数是params参数,而且它必须是参数表中的最后一个


Tuesday, October 19, 2004

  1. 数据的封装-对象
    1. 从本质上讲,对象就是数据。随着程序设计语言的发展,当人们开始把不同的数据组合在一起并当作一个整体事物来对待时,“对象”出世了!(拿日期对象作理解)
    2. 在声明变量和常数时,你的程序其实就是在创建对象,数值常数和字符串都是对象。不过,有你的程序真正执行有关语句之前,对象是不会“出生的”。
    3. 日期对象:日期是由三个分立的数型变量组合而成的有机整体,这样会大大简化对日期数据的处理。
  2. new操作符将为新实例分配内存并把它的的各个字段全部初始化为0;堆内永远是被初始化为的0的(就是堆栈可是值0或空指针null)。
  3. Date[] aDate = new Date[5];
    1. 如果Date是一个结构:这条语句将从堆里为这个结构的5个实例(无需new初始化了,叫实例了嘛)分配内存并把各元素的所有字段全部初始化为0;
    2. 如果是一个类,这条语句将只为这个数组本身分配内存(上面也会为数组本身分本内存,不过还为结构实例分配)。这个数组的各个元素将是null。因为这个数组的各个元素都是一个引用(指针)。在使用这个数组的元素前,必须先用一个new构造实例(包括分配内存和初始化):
      aDate[3] = new Date();
  4. C#数组是一个引用类型,数组中的各个元素将存储在堆里。如 int[] ai = new int[12];//使用new关键字在heap分配内存
  5. 除了数组,C#还有以下引用类型:
    The key of C# 学习笔记I-II_第1张图片
     
  6. 堆栈的执行效率要比堆的执行效率高,可是堆栈的资源有限,不适合处理大的逻辑复杂的对象。所以结构处理作为基类型对待的小对象,而处理某个商业逻辑
  7. 虽然结构的初始化也使用了new 操作符,可是结构对象依然分配在堆栈上而不是堆上,如果不使用“新建”(new),那么在初始化所有字段之前,字段将保持未赋值状态,且对象不可用
  8. 如何选择结构还是类
    讨论了结构与类的相同之处和差别之后,下面讨论如何选择使用结构还是类:
    1. 堆栈的空间有限,对于大量的逻辑的对象,创建要比创建结构好一些
    2. 结构表示如点、矩形和颜色这样的轻量对象,例如,如果声明一个含有 1000 个点对象的数组,则将为引用每个对象分配附加的内存。在此情况下,结构的成本较低。
    3. 表现抽象多级别对象层次时,是最好的选择
    4. 大多数情况下该类型只是一些数据时,结构时最佳的选择
  9. 面向过程到面向对象三步走:
    1. 封装对象简化输入参数列表:

      static int DayOfYear(int iYear, int iMonth, int iDay){....}//三个整型输入参数

      static int DayOfYear(Date dDate){....}//Date就好像是一个已预先定义好的简单类型

    2. 封装与对象有关的方法到类(或结构)内部中去,成为类(或结构)的行为,进一步共享代码
    3. 区分类(或结构)方法和字段的静态性和实例性,进一步简化使用对象的代码
  10. .NET Framewrok里的每一个类和每一个结构ToString方法,自已定义的类和结构也不例外,因为C#里所有类和结构都继承自同一个祖先——System.Object类。虽然结构不支持继承,但是所有的结构都是直接或间接从System.ValueType类继承而来的。
  11. 若一个实例方法的声明中含有 virtual 修饰符,则称该方法为虚拟方法。若其中没有 virtual 修饰符,则称该方法为非虚拟方法。
    非虚拟方法的实现是不会变的:无论是在声明它的类的实例上调用该方法还是在派生类的实例上调用,实现都是相同的。与此相反,一个虚拟方法的实现可以由派生类取代

  12. 关键字"virtual"和"override"是密切相关的:如果A类继承B类,就可以在A类里用一个override(重写)方法覆盖掉B类里的同名的virtual方法。

  13. 不使用"override"关键字也能覆盖一个方法,但这种做法只有新、老方法的签名和访问性完全一致的情况下才能达到目的


 

Wednesday, October 20, 2004

  1. 类的字段初始化方法:
    1. 在声明语句里直接初始化:

      class Date{
          public int iYear = 2004;
          public int iMonth = 10;
          public int iDay = 20;
          .......
      }

    2. 使用构造器:

      class Date{
          public int iYear, iMonth, iMonth; 
         
          public Date(){//无参数构造器
              iYear = 1;
              iMonth = 1;
              iDay = 1;
          }
          .......
      }

    3. 为了加快那些基于结构的数组创建速度,结构均不支持以上两种初始化结构的方法。
  2. C#的结构是一个关系重大的语言功能。和类一样,结构也可以包含其他类型。由于结构在内部是值类型的,所以结构有时也被称为类的轻型版本。同时,结构不承担引用对象所带来的开销,除非在对其装箱时例外。
  3. C#的结构结论:
    1. 结构的定义是封闭的(不能作为基类使用);
    2. 结构隐式地派生自System.ValueType,而System.ValueType是所有值类型的超类型(终极基类)。
    3. 结构没有默认的构造器
  4. 阻止创建类实例的方法:一个私有的(private)空白无参数构造器,如:class clsA{...private clsA(){}...}
  5. 实际上如果我们能够深刻地把握类的构造器的唯一目的就是保证类内的成员变量能够得到正确的初始化,我们对各种C#中形形色色的构造器便有会心的理解--它没有理由不这样!
  6.   ⒈﹜ ┣━┒ ; `.┣─┒`  ..wǒ
      個ボ ┟━┃┍╄┓┟━│ ╃━  
       人 ┝─┃┣╈┤┣━┃;/ ╈  
          ┗━┘┗┸┛└━┛/┃┻
  7. 相等性:
    当你自行创建一个类或结构时,一定要对相等性概念多做些思考。
  8. 要想成为一名合格的程序员,不仅要知道类对象和结构对象在相等性、赋值操作、方法调用等几个方面有何不同,还要了解new操作符对类对象和结构对象的处理有何不同。
    1. 要想创建出某个的一个实例,就必须使用一个new操作符,new操作符将进行几项非常重要的处理:
      1. 从堆里为新对象分配内存;
      2. 有选择地调用那个类的某一个构造器。
    2. 创建出某个结构的一个实例,也使用一个new操作符,new操作符将调用结构的惟一的无参数构造器(不能重写),无参数构造器只是把所有的字段初始化0或null而已,其他什么都不做。不允许字段非零和上面结构创建速度有关的。
  9.  Reference Types versus Value Types

以下是引用片段:
// Reference Type (because of ’class’)
class  Ref { public int x, y, cx, cy; }
// Value type (because of ’struct’)
struct Val { public int x, y, cx, cy; }
static void SomeMethod {
   Ref r1 = new Ref();  // Allocated in heap
   Val v1;              // Allocated on stack (new optional)
   r1.x = 10;           // Pointer dereference
   v1.x = 10;           // Changed on stack
   RectRef r2 = r1;     // Copies pointer only
   RectVal v2 = v1;     // Allocate on stack & copies members
   r1.x = 20;           // Changes r1 and r2
   v1.x = 20;           // Changes v1, not v2
}

 



Sunday, October 24, 2004

  1. 域的存取限制集中体现了面向对象编程的封装原则
  2. 只读(readonly)域不能进行写操作,不变常量(const)不能被修改,这两者到底有什么区别呢?
    1. 只读域只能在初始化--声明初始化或构造器初始化--的过程中赋值,其他地方不能进行对只读域的赋值操作,否则编译器会报错。只读域可以是实例域也可以是静态域。只读域的类型可以是C#语言的任何类型。
    2. 但const修饰的常量必须在声明的同时赋值,而且要求编译器能够在编译时期计算出这个确定的值。const修饰的常量为静态变量,不能够为对象所获取。const修饰的值的类型也有限制,它只能为下列类型之一(或能够转换为下列类型的):sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, string, enum类型, 或引用类型。能够声明为const的引用类型只能为string或值为null的其他引用类型。
  3. 实际上,如果我们能够理解const修饰的常量是在编译时便被计算出确定的值,并代换到引用该常量的每一个地方,而readonly时在运行时才确定的量--只是在初始化后我们不希望它的值再改变,我们便能理解C#设计者们的良苦用心,我们才能彻底把握const和readonly的行为!
  4. C#不提倡将域的保护级别设为public而使用户在类外任意操作--那样太不OO,或者具体点说太不安全!对所有有必要在类外可见的域,C#推荐采用属性来表达。属性不表示存储位置,这是属性和域的根本性的区别。
  5. 继承
    一个现有的类(基类)派生出一个新类(子类)时,子类将自动获得所有被声明在基类的非private方法、属性和字段(注意基类的构造器是不会被继承的。)。子类可以通过增加或者替换它继承到的各种方法、属性和字段的方式对基类的功能进行扩展
  6. 继承能力是类和结构的重要区别之一。结构不支持继承机制。
  7. 学海无涯,面向对象的程序设计既是一门科学,也是一门艺术,如果这本书能让大家领略到它的一些奥妙,作者知足了!!
  8. 继承与预构造器(constructor initializer)
    1. 每一个构造器都会用一个预构造器
    2. 子类不能继承基类的构造器但是可以“拿来用”,用关键字“base”指定父类和“this”指定本类中的构造器作为本构造器的预构造器。
    3. 在没有指定时,父类的无参数构构造器为缺省的预构造器,即:“base()”
  9. 访问限定符理解:
    很多新手认为代码共享就是最大限度的开放自己的代码,总是不假思索把所有东西都声明为“public”,其实类里面的public成员应该越少越好,因为可以降低调试难道,还遵循“尽量掩藏数据。使类成为一个代码黑箱”的原则。

Monday, October 25, 2004

  1. One of the more powerful concepts in object-oriented programming is polymorphism. The roots of this word, "poly-" and "-morph" mean, when put together, "many forms."
  2. polymorphism(破利摩飞神):“poly-”表示多之意,“-morph”,形态形状
  3. 多态实例:

    using System ;
    public class DrawingBase{
        public virtual void Draw(){//基类虚方法
            Console.WriteLine("I'm just a generic drawing object.");
        }
    }
    public class Line : DrawingBase{
        public override void Draw( ){//子类重写虚方法1
            Console.WriteLine("I'm a Line.");
        }
    }
    public class Circle : DrawingBase{
        public override void Draw( ){//子类重写虚方法2
            Console.WriteLine("I'm a Circle.");
        }
    }
    public class Square : DrawingBase{
        public override void Draw( ){//子类重写虚方法3
            Console.WriteLine("I'm a Square.");
        }
    }
    public class DrawDemo{
        public static int Main(string[] args){
            DrawingBase [] dObj = new DrawingBase [4];//创建基类类型数组
            dObj[0] = new Line( );//赋值类型向上转换
            dObj[1] = new Circle( );//声明(编译时)为基类类型,实际类型(运行时)为子类类型
            dObj[2] = new Square( );
            dObj[3] = new DrawingBase( );
            foreach (DrawingBase drawObj in dObj)
                drawObj.Draw( );//运行时“后绑定”各个Draw版本
            return 0;
        }
    }

  4. as 运算符
    1. 用于执行可兼容类型之间的转换。as 运算符用在以下形式的表达式中:expression as type
    2. as 运算符类似于类型转换,所不同的是,当转换失败时,as 运算符将产生空,而不是引发异常。
    3. 请注意,as 运算符只执行引用转换和装箱转换。as 运算符无法执行其他转换。
  5. is 运算符用于检查对象的运行时类型是否与给定类型兼容。
  6. GetType()方法与操作符typeof()System.Type
    1. Type t = instance.GetType();//一个实例方法,返回一个Type对象
    2. Type t = typeof(class);//一个操作符,操作数为一种类型非某一实例,也是返回一个Type对象
    3. 相等性比较:bool b = instance.GetType() == typeof(class);
  7. 所谓“实现一个接口”指的是把该接口所声   明的方法都在某个类里实现出来。
  8. 接口本质上是类需要如何响应的定义。接口描述类需要实现的方法、属性和事件,以及每个成员需要接收和返回的参数类型,但将这些成员的特定实现留给实现类去完成。
  9. 派生类可以重写(override)基类里的虚(virtual)方法和属性, 也可“隐藏”(new关键字)基类里的非虚成员。
  10. 操作符重载:()
    Operators are defined for the built-in types, but that's not all.  You can add operators to your own types, allowing them to be used much like the operators with the built-in C# types.

    Requirement:you create a Matrix type and then do a mathematical operation with them.

    Solution:

    1. implement an Add(), DotProduct(), and other methods to get the job done.

      Matrix result = mat1.Add(mat2);  // instance
      or
      Matrix result = Matrix.Add(mat1, mat2);  // static
      or event worse
      Matrix result = mat1.DotProduct(mat2).DotProduct(mat3); // and so on...

    2.  much easier to have a + operator for the add operation and a * operator for the dot product operation.

      Matrix result = mat1 + mat2;

      or

      Matrix result = mat1 * mat2;

      or even better

      Matrix result = mat1 * mat2 * mat3 * mat4;


你可能感兴趣的:(The key of C# 学习笔记I-II)