1. C#类型的取值范围

    名称 CTS类型 说明 范围
    sbyte System.SByte 8位有符号的整数 -128~127(27−1)
    short System.Int16 16位有符号的整数 -32 768~32 767(215−1)
    int System.Int32 32位有符号的整数 -2 147 483 648~2 147 483 647(231−1)
    long System.Int64 64位有符号的整数 263−1
    byte System.Byte 8位无符号的整数 0~255(0~28−1)
    ushort System.UInt16 16位无符号的整数 0~65535(0~216−1)
    uint System.UInt32 32位无符号的整数 0~4 294 967 295(0~232−1)
    ulong System.UInt64 64位无符号的整数 0~18 446 744 073 709 551 615(0~264−1)
  2. 访问限制符

    修饰符 应用于 说明
    public 所有类型或成员 任何代码均可以访问该项
    protected 类型和内嵌类型的所有成员 只有派生的类型能够访问该项
    internal 所有类型或成员 只能在包含它的程序集中访问该项
    private 类型和内嵌类型的所有成员 只能在它所属的类型中访问该项
    protected internal 类型和内嵌类型的所有成员 只能在包含它的程序集和派生类型的任何代码中访问该项
  3. C#常见的修饰符

    修饰符 应用于 说明
    new 函数成员 成员用相同的签名隐藏继承的成员
    static 所有成员 成员不作用于类的具体实例
    virtual 仅函数成员 成员可以由派生类重写
    abstract 仅函数成员 虚拟成员定义了成员的签名,但没有提供实现代码
    override 仅函数成员 成员重写了继承的虚拟或抽象成员
    sealed 类、方法和属性 对于类,不能继承自密封类。对于属性和方法,成员重写已继承的虚拟成员,但任何派生类中的任何成员都不能重写该成员。该修饰符必须与override一起使用
    extern 仅静态[DllImport]方法 成员在外部用另一种语言实现
  4. 结构体

    • 结构是值类型,不是引用类型。
    • 存储在栈中或存储为内联(inline)(如果它们是存储在堆中的另一个对象的一部分),其生存期的限制与简单的数据类型一样。
    • 结构体不支持继承。
    • 对于结构构造函数的工作方式有一些区别。尤其是编译器总是提供一个无参数的默认构造函数,它是不允许替换的。
    • 使用结构,可以指定字段如何在内存中的布局。
    • 注意,因为结构是值类型,所以new运算符与类和其他引用类型的工作方式不同。new运算符并不分配堆中的内存,而是只调用相应的构造函数,根据传送给它的参数初始化所有的字段。
    • 结构遵循其他数据类型都遵循的规则:在使用前所有的元素都必须进行初始化。在结构上调用new运算符,或者给所有的字段分别赋值,结构就完全初始化了。当然,如果结构定义为类的成员字段,在初始化包含的对象时,该结构会自动初始化为0。
    • 结构是会影响性能的值类型,但根据使用结构的方式,这种影响可能是正面的,也可能是负面的。正面的影响是为结构分配内存时,速度非常快,因为它们将内联或者保存在栈中。在结构超出了作用域被删除时,速度也很快。负面影响是,只要把结构作为参数来传递或者把一个结构赋予另一个结构(如A=B,其 中A和B是结构),结构的所有内容就被复制,而对于类,则只复制引用。这样就会有性能损失,根据结构的大小,性能损失也不同。注意,结构主要用于小的数据结构。但当把结构作为参数传递给方法时,应把它作为ref参数传递,以避免性能损失————此时只传递了结构在内存中的地址,这样传递速度就与在类中的传递速度一样快了。但如果这样做,就必须注意被调用的方法可以改变结构的值。
    • 结构不是为继承设计的。这意味着:它不能从一个结构中继承。唯一的例外是对应的结构(和C#中的其他类型一样)最终派生于类System.Object。因此,结构也可以访问System.Object的方法。在结构中,甚至可以重写System.Object中的方法————如重写ToString()方法。结构的继承链是:每个结构派生自System.ValueType类,System.ValueType类又派生自System.ObjectValueType并没有给Object添加任何新成员,但提供了一些更适合结构的实现方式。注意,不能为结构提供其他基类,每个结构都派生自ValueType
    • 为结构定义构造函数的方式与为类定义构造函数的方式相同,但 不允许定义无参数的构造函数。默认构造函数把数值字段都初始化为0,把引用类型字段初始化为null,且总是隐式地给出,即使提供了其他带参数的构造函数,也是如此。提供字段的初始值也不能绕过默认构造函数。
  5. 扩展方法

    • 扩展方法允许改变一个类,但不需要该类的源代码。所以使用扩展方法的情景之一是,当不知道类的源码或者不想修改该类的源码却想扩展该类,就可以用扩展方法。
    • 扩展方法是静态方法,它是类的一部分,但实际上没有放在类的源代码中。
    • 扩展方法需放在静态类中。
    • 对于扩展方法,第一个参数是要扩展的类型,它放在this关键字的后面。
    • 在扩展方法中,可以访问所扩展类型的所有共有方法和属性。
    • 如果扩展方法与类中的某个方法同名,就从来不会调用扩展方法。类中已有的任何实例方法优先。
  6. var关键字。编译器可以根据变量的初始化值“推断 ” 变量的类型。使用var关键字需要遵循的一些规则:

    • 变量必须初始化。否则,编译器就没有推断变量类型的依据。
    • 初始化器不能为空。
    • 初始化器必须放在表达式中。
    • 不能把初始化器设置为一个对象,除非在初始化器中创建了一个新对象。
  7. 密封类和密封方法

    • C#允许把类和方法声明为sealed。对于类,这表示不能继承该类;对于方法,这表示不能重写该方法。
    • 在把类或方法标记为sealed时,最可能的情形是:如果要对库、类或自己编写的其他类作用域之外的类或方法进行操作,则重写某些功能会导致代码混乱。也可以因商业原因把类或方法标记为sealed,以防第三方以违反授权协议的方式扩展该类。但一般情况下,在把类或成员标记为sealed时要小心,因为这么做会严重限制它的使用方式。即使认为它不能对继承自一个类或重写类的某个成员发挥作用,仍有可能在将来的某个时刻,有人会遇到我们没有预料到的情形,此时这么做就很有用。.Net基类库大量使用了密封类 ,使希望从这些类中派生出自己的类的第三方开发人员无法访问这些类。例如,string就是一个密封类。
  8. 约束

    • 泛型支持的几种约束类型:
    约束 说明
    where T : struct 对于结构约束,类型T必须是值类型
    where T : class 类约束指定类型T必须是引用类型
    where T : IFoo 指定类型T必须实现接口IFoo
    where T : Foo 指定类型T必须派生自基类Foo
    where T : new() 这是一个构造函数约束,指定类型T必须有一个默认构造函数
    where T1 : T2 这个约束也可以指定类型T1派生自泛型类型T2。该约束也称为裸类型约束
    • 只能为默认构造函数定义构造函数约束,不能为其他构造函数定义构造函数约束。
    • 在C#中,where子句的一个重要限制是,不能定义必须由泛型类型实现的运算符。运算符不能再借口中定义。在where子句中,只能定义基类、接口和默认构造函数。
  9. 复制数组

    • 如果数组的元素是值类型,调用Clone()方法就会复制所有值。如,int[] intArray1 = {1, 2}; int[] intArray2 = (int[])intArray1.Clone();其中intArray2数组的元素也变成了{1, 2}
    • 如果数组包含引用类型,则不复制元素,而只复制引用。
    • 除了使用Clone()方法之外,还可以使用Array.Copy()方法创建浅表副本。
    • Clone()方法和Copy()方法有一个重要区别:Clone()方法会创建一个新数组,而Copy()方法必须传递阶数相同且有足够元素的已有数组。
    • 如果需要包含引用类型的数组的深层副本,就必须迭代数组并创建新对象。
  10. Array类使用QuickSort算法对数组中的元素进行排序。Array类中的Sort()方法需要数组中的元素实现IComparable接口。简单类型(如System.String和System.Int32)已经实现了IComparable接口。

  11. 元组

    • 数组合并了相同类型的对象,而元组合并了不同类型的对象。
    • .NET 4定义了8个泛型Tuple类和一个静态Tuple类,不同泛型Tuple类支持不同数量的元素。例如,Tuple<T1>包含一个元素,Tuple<T1, T2>包含两个元素,以此类推。
    • 代码示例:

       1 public class TupleExample
       2 {
       3     static void Main()
       4     {
       5         TupleExample example = new TupleExample();
       6         var result = example.Divide(5, 2);
       7         Console.WriteLine("result of division: {0}, reminder: {1}", result.Item1, result.Item2);
       8     }
       9 
      10     public static Tuple<int, int> Divide(int dividend, int divisor)
      11     {
      12         int result = dividend / divisor;
      13         int reminder = dividend % divisor;
      14 
      15         return TupleExample.Create<int, int>(result, reminder);
      16     }
      17 }
      View Code

相关文章: