1. 面向对象的特征

    1. 统一的类型系统,有一个共同的基类object

    2. 类和接口 Class和Interface

    3. 唯一一种函数成员(Function Member)--方法 (Method),方法还包括属性(Property)和事件(Event)还有其他的

    4. 借用了不少函数式编程的特征

      1. 委托 Delegate

      2. 支持纯(purity)模式

        • 避免使用值可变的变量
  2. 类型安全

    1. 静态类型 static typing

    2. 动态类型 dynamic

    3. 强类型 strongly typed language

  3. 内存管理

    1. 依赖运行时来执行自动内存管理

    2. CLR Common Language Runtime 公共语言运行时

      1. GC Garbage Collector 垃圾收集器
    3. c#没有消灭指针

      1. 通常情况下不需要使用指针

      2. unsafe关键字

  4. 类型转换

    1. 隐式转换是自动进行的,编译器可以保证转换会成功,信息不会丢失

      1. 目标类型可以容纳源类型的时候
    2. 显示转换是手动进行的,编译器不能保证转换会成功,信息可能会丢失

    3. 如果编译器可以断定转换肯定会失败,那么转换会被禁止

  5. 值类型vs引用类型

    1. 包含所有的内置类型(数值,字符,bool)和自定义的strcut和enum

      1. 值类型变量/常量的内容就是一个值

      2. 赋值总是复制了该实例

      3. 所占的内存等于它的字段需要内存的总和

    2. 引用类型包含所有的class,数组,delegate,interface类型和字符串

      1. 它的内容就是到一个含有值的对象的引用

      2. 赋值复制该对象的引用而不是对象实例

      3. 允许多个变量引用同一个对象

      4. CLR会把类型内的字段大小设置为该字段实际大小的整数倍

      5. 需要为 引用 和 对象 单独分配内存

      6. 对象所占内存 = 其字段所占内存总和 + 额外的管理开销(最小8个字节)

      7. 每个对象的引用还需要额外的4或8个字节(根据平台是32位还是64位)

    3. 根本区别在于内存的处理方式

  6. 内置类型的分类

    1. 内置类型在System命名空间

    2. 除了decimal之外的内置类型叫做原始类型

    3. System.IntPtr 和 System.UIntPtr 也是原始类型

    4. 值类型

      • 数值型

        • 有符号整型 Signed integer(sbyte,short,int,long)

        • 无符号整型Unsigned integer(byte,ushort,uint,ulong)

        • 实数(float,double,decimal)

      • 逻辑(bool)

      • 字符(char)

    5. 引用类型

      1. 字符串(string)

      2. 对象(object)

  7. 编译器会推断一个数值Literal是double还是整数类型

    1. 如果包含小数点,或以指数形式展现,那么就是double类型

    2. 否则literal的类型是下面列表里第一个能容纳该数值的类型:int,uint,long,ulong

  8. 数值的后缀

    1. U、L、UL很少使用,因为uint、long、ulong要么可以被推断出来,要么可以从int隐式转换过来

    2. D 其实很多余,小数默认是double

    3. F、M是比较有用的,当指定float或decimal的Literal的时候,应该加上

  9. Overflow 溢出

    1. 在运行时,整型的算术操作可能引起溢出

    2. 默认情况下,不会抛出异常,可使用checked溢出检查,unchecked关闭溢出检查

    3. 结果类似于“环绕”这种行为

    4. int.MaxValue++ == int.MinValue

  10. 运算

    1. byte、sbyte、short、ushort 没有自己的算术操作符,C#会按需对它们进行隐式转换到大一点的整数类型
  11. double 和 decimal 都不可以精确的表达循环数据

  12. 相等和比较操作符

    1. 对于值类型(原始类型)来说,== 和 != 就是比较它们的值

    2. 对于引用类型,默认情况下,是比较它们的引用

    3. 数值类型都可以使用这些操作符:==,!=,<,>,<=,>=(实数还是需要注意一下)

    4. 枚举类型(enum)也可以使用这些操作符,就是比较它们底层对应的整型数值

创建类型

  1. 构造函数

    1. 构造函数里调用重载的其他构造函数时,使用this

    2. 构造函数可以为private

    3. 字段初始化发生在调用函数执行前,按照字段的先后顺序初始化

    4. Deconstrcut

      class Wine
      {
          public Wine(int a)
          {
      
          }
          public Wine(int a, int b) : this(a)//调用Wine(int a),
          {
      
          }
          Wine()//私有构造函数
          {
      
          }
          public static Wine GetInst()
          {
              return new Wine();//静态方式中调用私有构造函数
          }
          static wine(){
              Console.Write("");//静态构造函数,在类型使用之前,编译器自动调用
          }
      }
  2. 属性和字段相比多了一个get,set块

  3. 索引器,public string this[int index] => str[index];

  4. 常量的类型可以是内置的数值类型、bool、char、string或enum

  5. 静态类的成员都是静态的,不允许有子类

  6. 分布类,使用partial关键字,如果有父类,可以在一个或多个分布类指明,但必须一致

  7. 继承

    1. 一个类只能有一个父类,但一个父类可以用多个子类
    2. 多态,类型为X的变量可以引用其子类的对象
    3. 函数成员为virtual时,子类使用override重写
  8. 装箱和拆箱

    1. 装箱Box是把值类型转换为引用类型,可能是隐式转换
    2. 拆箱Unbox是把引用类型转换为值类型,拆箱是显示转换
    3. 拆箱时会检查这个类型和真实的类型是否匹配,如果不匹配会抛InvalidCaseException
  9. 所有内置类型都重写了ToString方法

  10. struct

    1. struct是值类型,class是引用类型

    2. struct不支持继承,除了隐式继承了object,具体点就是System.ValueType

    3. 不能有无参构造函数,不能声明字段的时候直接初始化,终结器,virtual或protected(不能继承这两种就没有意义了)

    4. 默认有一个无参构造函数,但是不能重写,他会对字段进行按位归零操作

    5. 定义struct构造函数的时候,必须显示的为每个字段赋值

      public struct Point
      {
          int x = 1;//不能有初始化器
          int y;
          int z;
          public Point()//不能重写无参构造函数
          {
      
          }
          public Point(int y)
          {
              //构造函数必须为所有字段初始化
              this.y = y;
          }
      }
  11. 5个访问修饰符

    1. public,完全可访问。enum和interface的成员默认都是这个级别

    2. internal,当前assembly或朋友assembly可访问,非嵌套类型的默认访问级别,

      通过System.Runtime.CompilerServices.InternalsVisibleTo特性指定朋友assembly

    3. private,本类可访问。class和struct的成员的默认访问级别。

    4. protected,本类或其子类可以访问。

    5. protected internal,联合了protected和internal的访问级别。

  12. 子类重写父类成员时,访问修饰符必须一致

  13. 接口

    1. 接口成员都是隐式抽象的,隐式public,不可以声明访问修饰符
    2. 一个class或struct可以实现多个接口
    3. 接口可以继承其他接口
    4. 实现多个接口时可能成员签名冲突,通过显示实现接口成员解决(接口名.成员名),显示实现的接口成员不可以被标记为virtual
  14. 枚举

    1. 每个枚举对应一个底层的整型数值
  15. 泛型

    1. 跨类型的可复用代码,带用类型占位符(T)的模板

    2. 泛型的约束

      1. where T : base-class//继承与某类
      2. where T : interface//实现了某接口
      3. where T : class //引用类型
      4. where T : struct //值类型 Nullable
      5. Where T : new()//有一个无参构造函数
      6. where K : T//K继承与T
    3. 泛型类型的子类

      1. 在子类里可以继续让父类的类型参数保持开放 class B : A{...}

      2. 使用具体的类型来封闭父类类型参数 class B : A{...}

      3. 子类可以引入新的类型参数 class B<T , K> : A{...}

      4. 子类为父类的类型参数带来新的名称或含义

        class A<T>{...}
        class B<Telement , Tkey> : List<Telement>//与父类T名字不一样
    4. 可以把自己作为具体的类型

      class interface A<T>{...}
      class B : A<B>{...}
    5. 针对每一个封闭类型,静态数据是唯一的

      class Bob<T>{ public static int Count; }
      
      Console.WriteLine(++Bob<int>.Count);//1
      Console.WriteLine(++Bob<int>.Count);//2
      Console.WriteLine(++Bob<string>.Count);//1
      Console.WriteLine(++Bob<object>.Count);//1
    6. 协变逆变

      1. Covariance out协变,输出参数,返回类型

        public interface IEnumerable<out T>{...};
        
        List<string> strings = new List<string>();
        IEnumerable<object> objects = strings;//子类的T转为父类的T
        
        var g1 = Get<int>();
        object g2 = g1;//相当于子类隐式转换为父类
                  //本来返回的是int类型,把返回值类型改成object
        public static T Get<T>()
        {
            return default(T);
        }
      2. Contravariance in 逆变输入参数,接收类型

        Action<object> action = (a) => Console.WriteLine(a);
        Action<string> objA = action;
        
        Action<object> action = Set;
        Action<string> objA = action;
        action(1);
        objA("a");//本来接收object类型,但我传的是string
        public static void Set(object i)
        {
            Console.WriteLine(i.ToString());
        }
      3. Invariance不变 既是输入,又是输出

  16. 可空值类型

    1. null有两种含义

      1. null引用

      2. 可空值类型HasValue为false时的值

        这两种写法是等价的

        int? a = new int?();

        int? a = null;