结构
    结构是值类型,派生自System.ValueType类,结构不能继承实现,但可以继承接口
    结构可以定义函数(方法)
    结构有构造函数,结构使用new时并不分配堆中内存,只是调用构造函数来初始化属性而已。

    虚方法
    在基类中用virtual标记虚方法,在派生类中用override标记重写虚方法,虚方法需显示指定,否则默认情况下不认为是虚方法、虚属性同理。
    重写基类的方法时,签名(参数和方法名)和返回类型必须完全匹配,否则,以后创建的新成员是不会覆盖基类成员的。
    成员字段和静态方法不能声明为virtual。

    多态性
    如果基类的方法不是虚拟方法或派生类的方法没有重写虚方法,就使用所声明对象的类型的方法
    image.pngimage.pngimage.pngimage.png
    如果基类Animal的Call方法采用virtual方法,Dog类override重写该方法,则会输出“狗叫声”

    隐藏方法
    如果签名(参数和方法名,返回类型相同)相同的方法在基类和派生类中都进行了声明,但该方法没有声明为virtual和override,派生类方法就会隐藏基类方法(调用的时候,而不是多态)

    抽象类和抽象方法
    如果类包含抽象方法,则该类也是抽象的,也必须声明为抽象的。抽象方法本身也是虚拟的(尽管不需要写virtual关键字)

    密封类和密封方法
    sealed关键字,不允许创建子类或重写方法
    密封类的一个好处是编辑器知道这个是密封类,不能派生类,因此用于虚拟方法的虚拟表可以缩短或消除,以提交性能。string类就是密封类。
    把类标记为saled对编译器来说是一个很好的提示。
    将一个方法声明为sealed的目的类似于一个类,方法必须是基类的重写方法才可以密封,密封的方法,如果有另一个类继承此类,则不能再重写此方法
    只能密封有继承的类和方法(说法不严谨),例如类都是继承于object所以都能密封,方法必须是重写基类的方法才能密封,否则不能密封。

    接口
    接口只能包含方法、属性、索引器、事件的声明,不能包含字段。

    Is
    is运算符根据条件是否满足,判读对象是否使用指定的类型,返回true或false
    if(obj is string){…}

    栈、堆
    栈:先进后出,后进先出。值类型基本都放在栈内存中,引用类型的引用地址也基本放在栈上,栈有非常高的性能,但灵活度不高
    堆:

    ① Customer arabel;
    ② arabel = new Customer();
    解释代码:
    ① 声明了一个Customer的引用arabel,在栈上给这个引用分配了存储空间。
    ② 首先在堆上分配内存,用来存储Customer对象,然后把变量arabel的值设置为分配Customer对象的堆上地址。

    using

    • 声明用于导入的名称空间。
    • 处理实现IDisposable的对象,并在作用域的末尾调用Dispose方法。

    装箱和拆箱
    值类型转换为引用类型称为装箱。
    引用类型转换为值类型称为拆箱。

    协变和抗变
    协变和抗变指对参数和返回值的类型进行转换。
    参数类型是协变的。 参数为Shape类,则派生自Shape的子类都可以传入作为参数。
    方法的返回类型是抗变的。返回类型是Shape类,则派生自Shape的子类不能作为返回。
    out 标记为协变
    in 标记为抗变

    Action和Func委托
    Action委托表示引用一个void返回类型的方法,可以传递至多16种不同的参数类型。
    Func委托允许调用带返回类型的方法,可以传递至多16种参数类型和一个返回类型
    Func可以调用带一个参数的方法,返回类型为TResult

    Lambda
    lambda运算符”=>”的左边列出了需要的参数,而右边定义了赋予lambda变量的方法的实现代码。
    如果参数只有一个:Func oneParm = s=> ….代码
    如果参数有多个:Func towParms =(x,y)=> …代码
    通过lambda表达式可以访问lambda表达式块外部的变量,这称为闭包

    Linq
    from x in objList where x.id ==1 orderby x.id descending select x;
    查询表达式必须以from子句开头,以select或group子句结束。在这两个子句之间,可以使用where、orderby、join、let和其他from子句。

    本质上讲委托是一个类型安全的对象,它指向程序中另一个以后会被调用的方法(或多个方法)
    委托有同步行为和异步行为。

    进程、引用程序域、上下文
    线程是可执行引用程序中的基本执行单元。
    进程是一个运行程序,进程和进程之间是相互隔离的。
    进程的入口点创建的第一个线程被称为主线程。
    无论是主线程还是次线程,都是进行中的一个独立执行单元,他们能够同时访问那些共享数据。
    .NET可执行程序承载在进程的一个逻辑分区中,称为应用程序域(AppDomain)。
    一个进程可以包含多个应用程序域
    委托同步调用 Invoke()
    委托异步调用 BeginInvoke()和EndInvoke()
    示例演示如何用委托来自动创建次线程以处理异步方法调用。
    image.png

    Thread 是一个面向对象的包装器,包装特定应用程序域中的某个执行单元。
    image.png

    前台线程 能阻止应用程序的终结,只有当所有前台线程都终止后,CLR才能关闭应用程序(即卸载承载的应用程序域)。
    后台线程 也叫守护线程,被CLR认为是程序可以牺牲的,当应用程序域卸载时,所有的后台进程也会被自动终止。

    lock
    关键字lock是同步访问共享资源的首选。
    C#的赋值和数值运算都不是原子型操作。
    image.png
    几种原子操作
    image.png
    image.png

    线程池
    image.png
    线程池中的线程总是后台线程
    使用线程池的好处:

    • 线程池减少了线程的创建、开始、停止的次数,而这提高了效率。
    • 使用线程池,能够是我们将注意力放到业务逻辑上而不是多线程架构上。

    构建多线程可以使用的技术

    • 委托
    • 通过System.Threading的成员
    • TPL任务并行库 (.NET 4.0以上)
    • async和await关键字 (.NET 4.5以上)

    TPL 任务并行库
    System.Threading.Tasks中的类型被称为任务并行库(TPL)
    TPL使用CLR线程池自动将应用程序的工作动态分配到可用的CPU中,TPL还处理工作分区、线程调度、状态管理和其他低级别的细节操作。最终结果就是,可以最大限度的提升.NET应用程序的性能,并且避免直接操作线程所带来的复杂性。
    image.png

    Parallel.For()和Parallel.ForEach()方法以并行方式对数组或集合中的数据进行迭代。

    async 和 await
    async关键字用来指定某个方法、lanbda表达式或匿名方法自动以异步的方式来调用。CLR会创建新的执行线程来处理任务。在调用async方法时,await关键字会自动暂停当前线程,直到async标记的方法在另外的线程执行完,才继续当前的线程。

    程序集
    提供了公钥信息的程序集被称为强命名的
    程序集可以以“私有”或者“共享”的方式部署,私有程序集与调用它的客户端应用程序处于同一个目录下或子目录中。而共享程序集则事为了让同一台机器上的大部分程序都可以使用而存在的代码库,它被部署在全局程序集缓存(GAC)的特定目录中。