C# 相关知识点

CLR是公共语言运行库(Common Language Runtime)的缩写,是微软为.NET产品构建的运行环境,类似于Java的JVM(Java虚拟机)。

CLR是所有.NET应用程序的运行时环境,提供了内存管理、程序集加载、安全性、异常处理和线程同步等核心服务

深拷贝与浅拷贝

浅拷贝是指向和拷贝对象相同的内存地址,因为是共用一个地址,所以当拷贝对象发生变化时,我们新的对象也会发生变化。
深拷贝的话,我们是开辟了一块新的内存地址来存放新的对象,这样两个对象是指向不同内存地址,所以对于被拷贝对象进行修改时,不会影响到拷贝的对象。

实现深拷贝采用递归法或者json的序列化与反序列化。

懒加载(Lazy Loading)是一种延迟加载技术,指在需要使用某个对象或数据时才进行加载,而不是在系统启动或加载时就立即加载。懒加载可以在一定程度上提高系统的性能和资源利用率。

在应用程序中,懒加载通常应用于以下场景:

数据库访问:在访问数据库时,可以采用懒加载技术,只有在需要使用数据时才进行查询,而不是一次性将所有数据都查询出来,避免数据量过大导致内存溢出或查询时间过长的问题。

图片加载:在访问网页时,可以采用懒加载技术,只有当图片出现在浏览器可视范围内时才进行加载,避免一次性加载所有图片导致页面加载时间过长或带宽消耗过大的问题。

模块加载:在使用模块时,可以采用懒加载技术,只有在需要使用模块时才进行加载,而不是在系统启动或加载时就立即加载所有模块,避免系统启动时间过长或内存消耗过大的问题。

Socket通信

一.Socket其实并不是一个协议,而是为了方便使用TCP或UDP而抽象出来的一层,是位于应用层和传输控制层之间的一组接口.

当两台主机通信是,必须通过Socket连接,Socket则利用TCP/IP协议建立TCP连接.TCP连接则更依赖于底层的IP协议.Socket是控制层传输协议.

二.网络通信三要素
IP地址(网络上主机设备的唯一标识)
端口号(定位程序)
 有效端口:0~65535,其中0~1024由系统使用,开发中一般使用1024以上端口.
传输协议(用什么样的方式进行交互)
常见协议:TCP(面向连接,提供可靠的服务),UDP(无连接,传输速度快)

三.C#Socket简单使用

第一步:服务端监听某个端口

第二步:客户端向服务端地址和端口发起Socket请求

第三步:服务器接收连接请求后创建Socket连接,并维护这个连接队列

第四步:客户端和服务端就建立起了双工同信,客户端与服务端就可以实现彼此发送消息

int 和 integer

数据类型和默认值。int是Java的一种基本数据类型,默认值是0;Integer是int的包装类,属于引用类型,默认值是null。

内存存储方式。Integer是一个对象,存储在堆内存中;int是基本数据类型,直接存储在栈空间中。

实例化。Integer变量必须通过实例化才能使用;int变量不需要实例化,可以直接使用。

String.Empty 和" " 和null

String.Empty 和" " 都会在栈上分配一个空间,保存的是堆上一个长度为0的内存地址

null不会在堆上开辟内存空间

ref和out

ref:通过引用类型的方式传值,返回的是操作后的变量,必须传一个有值的变量

out:可以传空值

virtual:虚函数

虚函数在编译期间是不被静态编译的,它的相对地址是不确定的,它会根据运行时期对象实例来动态判断要调用的函数

子类继承父类,如果声明类(即父类)中此函数是virtual修饰的,则先查找本类是否有重写或重新声明此方法。

有则执行子类的方法,没有则一层层的往上查找父类,直到找到重写过该方法的父类,然后执行此方法。

abstract:抽象方法

有抽象方法一定是抽象类,抽象类不一定有抽象方法

抽象类不能被实例化,抽象方法没有具体的实现

无法使用 sealed 修饰符来修改抽象类,因为两个修饰符的含义相反。 sealed 修饰符阻止类被继承,而 abstract 修饰符要求类被继承。

抽象方法不能用static 或 virtual 修饰,子类必须要重写父类的抽象方法

因为抽象类不能被实例化,所以调用抽象类中的非抽象方法,就要子类继承抽象类,然后实例化子类调用父类非抽象方法

override:

不能重写非虚方法或静态方法。 重写基方法必须是 virtualabstract 或 override(已经被重写过的方法可再次被重写)

不能使用 newstatic 或 virtual 修饰符修改 override 方法。

重写属性声明必须指定与继承的属性完全相同的访问修饰符、类型和名称,并且重写的属性必须是 virtualabstract 或 override

Interface:

接口也是只有声明,没有实现,但是跟抽象方法不同的是,子类实现接口必须全部重写接口成员,子类继承抽象类只需要重写抽象方法。

编程更加规范,解耦

静态变量与非静态变量的区别
1.内存分配 
静态变量在应用程序初始化时,就存在于内存当中,直到它所在的类的程序运行结束时才消亡; 
而非静态变量需要被实例化后才会分配内存。 
2.生存周期 
静态变量生存周期为应用程序的存在周期; 
非静态变量的存在周期取决于实例化的类的存在周期。 
3.调用方式 
静态变量只能通过“类.静态变量名”调用,类的实例不能调用; 
非静态变量当该变量所在的类被实例化后,可通过实例化的类名直接访问。 
4.共享方式 
静态变量是全局变量,被所有类的实例对象共享,即一个实例的改变了静态变量的值,其他同类的实例读到的就是变化后的值; 
非静态变量是局部变量,不共享的。 
5.访问方式 
静态成员不能访问非静态成员; 
非静态成员可以访问静态成员。

静态成员越少声明越好,比较占内存。

6.静态方法不能被重写

静态类里面成员必须全部是静态的。

partial:分类

将类、结构或接口的定义拆分到两个或多个源文件中,在类声明前添加partial关键字即可。

编译时会合并成一个类

多线程

为了充分利用服务器性能,让程序并发进行,提高执行效率,引入多线程

1. 可以使用Thread类

2. Task和Task类是.NET Framework 4.0引入的一种高级多线程编程模型

3. 异步和await关键字是C# 5.0引入的一种编程模型。它们允许将异步操作与同步代码结合起来,使代码更简洁易读。

4. 并行编程库(Parallel类)提供了一些方便的方法来进行并行计算,如Parallel.ForEach和Parallel.For。它会自动将任务拆分成多个子任务,并利用多个线程并发执行。

线程池

同时频繁地创建和销毁线程是会消耗性能的,所以引入了线程池,可以对线程管理和重复利用

使用ThreadPool类:ThreadPool类是一个线程池,它可以管理和复用线程。你可以使用ThreadPool.QueueUserWorkItem方法将一个方法放入线程池中进行执行。

当应用程序想要执行一个异步操作时,你需要调用QueueUserWorkItem方法来将对应的任务添加到线程池的请求队列中。线程池实现的代码会从队列中提取任务,并将其委派给线程池中的线程去执行。

如果线程池中没有空闲的线程,线程池就会创建一个新线程去执行提取的任务。而当线程池线程完成了某个任务后,线程也不会被销毁,而是返回到线程池中,等待响应另一个请求。

线程安全

一般为了保证线程安全,会对全局变量加锁 lock(变量),来保证同一时刻只有一个线程来访问共享变量。

一个标准的锁对象应该是私有的、静态的、只读的、引用类型的对象,这样可以防止外部改变锁对象。

同时为了避免死锁,使用互斥锁Monitor可以给锁设置超时时间。

async和await

两者一般搭配使用,async表示要异步执行,执行到await会回调子线程,子线程执行完毕才继续执行await之后的,这段程序可能是子线程执行也可能是主线程执行。

懒加载

懒加载其实就是延时加载,即当对象需要用到的时候再去加载。

可以减少与数据源的交互(数据量而不是交互次数)

现在用include代替

接口

使程序更干净、更精简、更容易设计和维护、更容易增强

数据库锁

并发可能导致的影响:

1. 丢失更新:多个事务同时更新同一行;

2. 脏读:修改过程中的数据被读取;

3. 不一致的分析(不可重复读):读取的事务里面,符合读取条件的行搜索条件被更改了;

4. 幻读:读取的事务里面,符合读取条件的行被删除或者插入了;

1. 悲观并发控制:用到锁来保护数据。用于锁消耗低于回滚事务的成本环境中;

2. 乐观并发控制:并发过程中不产生锁,读取数据后检查用户数据,判断是否产生错误, 回滚事务。用于数据争用少的环境。

1. 共享锁(S) :读取产生的锁,防止其他事务对其的修改;

2. 更新锁(U) :可防止死锁,在共享锁与排他锁之间,与共享锁兼容,与排他锁不兼容。

3. 排他锁(X) :用于数据增删改操作。锁定时数据无法修改与读取(在nolock或未提交读隔离级别时可以脏读)

OOA/OOD和UML

OOA指的是面向对象的分析,OOD指的是面向对象的设计。

UML是统一建模语言,在软件开发中,一般用于面向对象的分析设计建模。

也就是说,我们要利用面向对象语言开发一个系统,要做该系统的分析和设计,就需要用到UML进行分析设计建模。

面向对象、面相过程

多继承构造函数调用关系

class A;

class B: virtual public A;

class C: virtual public A;

class E;

class D:public B, public C

其中E是D的子对象

B和C都是虚继承自A,New一个D对象时,先调用A的构造函数,然后D继承类的的顺序调用 B-->C的构造函数;

然后调用子对象构造函数,因为构造子对象E是构造D的任务的一部分,最后才是D本身

如何保证Api的安全性

  1. Token授权认证,防止未授权用户获取数据,且Token是唯一的,过期重新获取等;

  2. 时间戳超时机制;

  3. URL签名,防止请求参数被篡改;

  4. 防重放,防止接口被第二次请求,防采集;

  5. 采用HTTPS通信协议,防止数据明文传输;

单机、集群、分布式、微服务

单机结构,即系统业务量很小的时候所有的代码都放在一个项目中,项目部署在一台服务器上。整个项目所有的服务都由这台服务器提供。单机结构的缺点就是处理能力有限,当业务增长到一定程度的时候,单机的硬件资源将无法满足业务需求。此时便出现了集群模式

集群模式,单机处理到达瓶颈的时候,你就把单机复制几份,这样就构成了一个“集群”。集群中每台服务器就叫做这个集群的一个“节点”,所有节点构成了一个集群。每个节点都提供相同的服务,那么这样系统的处理能力就相当于提升了好几倍。

但问题是用户的请求究竟由哪个节点来处理呢?最好能够让此时此刻负载较小的节点来处理,这样使得每个节点的压力都比较平均。要实现这个功能,就需要在所有节点之前增加一个“调度者”的角色,用户的所有请求都先交给它,然后它根据当前所有节点的负载情况,决定将这个请求交给哪个节点处理。这个“调度者”就是——负载均衡服务器。

集群结构的好处就是系统扩展非常容易。如果随着你们系统业务的发展,当前的系统又支撑不住了,那么给这个集群再增加节点就行了。但是,当你的业务发展到一定程度的时候,你会发现一个问题——无论怎么增加节点,貌似整个集群性能的提升效果并不明显了。这时候,你就需要使用微服务结构了。

分布式结构,就是将一个完整的系统,按照业务功能,拆分成一个个独立的子系统,在分布式结构中,每个子系统就被称为“服务”。这些子系统能够独立开发,独立运行,独立部署。

  • 系统之间的耦合度大大降低,系统与系统之间的边界非常明确,排错也变得相当容易,开发效率大大提升。
  • 系统更易于扩展。可以针对性地扩展某些服务。
  • 服务的复用性更高。比如,当我们将用户系统作为单独的服务后,该公司所有的产品都可以使用该系统作为用户系统,无需重复开发。

微服务和分布式性质差不多,微服务可以放在Docker容器中统一管理。

Redis缓存

Redis缓存的作用就是减少对数据库的访问压力,当我们访问一个数据的时候,我们先从redis中查看是否有该数据,如果没有,则从数据库中读取,将从数据库中读取的数据存放到缓存中,下次再访问同样的数据的是,还是先判断redis中是否存在该数据,如果有,则从缓存中读取,不再访问数据库,减小数据库的压力。

服务器性能、负荷

负载能够直接反应服务器当前的状态。load average 表示机器一段时间内的平均load,这个值越低越好,负载过高会导致机器无法处理其他请求及操作,甚至导致死机。最先考虑的是使用性能更好地服务器。其次项目我们需要考虑。

1、是否有内存泄露导致频繁GC 

2、是否有死锁发生 

3、是否有大字段的读写 

4、会不会是数据库操作导致的,排查SQL语句问题。

C#内存相关

c#自带垃圾回收机制,当内存不足或者程序运行结束时GC会自动回收位于托管堆上的对象。当然从名字我们也会看出这是针对托管资源,而对于非托管资源,则可通过

1.析构函数:调用对象的Finalize方法销毁对象。

2.继承IDisposable接口,实现Dispose()方法。

3.对于数据库连接可以使用 Using,会自动调用finally方法释放资源。

4.可以使用单例模式,避免重复的创建对象。

单例模式:一个私有构造器,一个getInstance方法。

托管资源:大部分引用类型。

非托管资源:文件流,数据库的连接,打印机资源等。

值类型 值存在栈中。

引用类型值存在堆上,栈中存在的是堆得地址。

声明一个类时,先在栈上分配一个空间等待存储堆中的地址,new一个对象时才分配堆中的空间,并把地址赋值给栈。

1.表连接的SQL语句,对于内连接 inner join来说,join语句和把条件写在where语句里结果一样,但是对于左连接和右连接就不一样了,例如左连接,on后面的条件只对右表有效,对左表的筛选就要写在where里面。而且join on是先把两张表笛卡儿积组成一张表,再用where条件筛选,对于join很多表来说,从左往右,左边的表越小效率越高。所以尽量把条件写在on里面可以提高效率。

2.用Dapper框架的时候,尽量不要用拼接字符串的形式组SQL,因为有被攻击或者SQL注入的风险,尽量用StringBulder。

Dapper.Query()  返回查询结果                            参数一般为  SQL语句,参数变量,事务,SQL类型(SQL语句或者存储过程)

Dapper.Execute() 返回受影响的行数

GET请求和POST请求

1.GET和POST是http协议的两种请求方式,GET一般用来请求数据,POST一般用来传递参数用于更新等。

2.GET请求会把参数带在URL,对用户是可见的,而POST是把参数放到请求体中,但GET也可以把参数放到请求体中,但是服务器不一定能接收到

3.POST请求相对于GET请求更安全。因为GET请求传递的参数会显示在url中,用户在访问的时候浏览器会缓存网页,这样别人在查看浏览器浏览记录的时候会获取私人信息,POST请求不会被用户看到,所以安全性高。

4.GET请求在URL中传送的参数是有长度限制的,而POST么有。

5.对参数的数据类型,GET只接受ASCII字符,而POST没有限制。

6.对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);

而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。但并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。

EntityFrameWork 和 .NET Core对比

不能说Core一定比EF好,但是Core有一个最大的优点是跨平台,开源,而且比较多的IDE支持Core(VS ,VS CODE),而EF相对来说更加稳定,EF应用也更广泛,另外WCF服务和窗体不支持Core

但是当客户有以下需求时我们更应该考虑Core

  • 用户有跨平台需求。
  • 用户正在面向微服务(Azure)。
  • 用户正在使用 Docker 容器。
  • 需要高性能和可扩展的系统。
  • 需按应用程序提供并行的 .NET 版本(不同版本的.net core(可能是2.0 和3.0),像EF可能就是4.0  或者 4.1)。

3.String和StringBuilder

string本身是不可改变的,它只能赋值一次,每一次内容发生改变,都会生成一个新的对象,然后原有的对象引用新的对象,而每一次生成新对象都会对系统性能产生影响,这会降低.NET编译器的工作效率

而StringBuilder类则不同,每次操作都是对自身对象进行操作,而不是生成新的对象,其所占空间会随着内容的增加而扩充

当程序中需要大量的对某个字符串进行操作时,应该考虑应用StringBuilder类处理该字符串,其设计目的就是针对大量string操作的一种改进办法,避免产生太多的临时对象;而当程序中只是对某个字符串进行一次或几次操作时,采用string类即可。

4.ASP.NET和.NET的区别:

.Net是平台,下面包括很多种语言,比如C#,VB,C++等,而且.NET有主要分为两部分,WinForm(CS)和WebForm(BS),而ASP.NET属于.NET下的一部分,主要用来做WebForm项目。编译后形成CLR(中间语言),然后通过服务器的IIS+.Net FrameWork再次编译来运行。


5.委托

引用类型,用delegate来声明,参数和返回类型和对应的方法相同

使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。

系统本身有两个定义好的委托类型,其中Action是无返回值(void)类型方法,Func有返回值


6.装箱与拆箱

装箱就是隐式的将一个值型转换为引用型对象。
拆箱就是将一个引用型对象转换成任意值型。
比如:
int i=0;
Syste.Object obj=i;
这个过程就是装箱!就是将 i 装箱!

比如:
int i=0;
System.Object obj=i;
int j=(int)obj;
这个过程前2句是将 i 装箱,后一句是将 obj 拆箱!

7.BS和CS架构的优缺点

B/S 浏览器端/服务端 : 开发成本低,版本永远是最新的,适用范围广,对安全的控制能力相对弱, 面向是不可知的用户群.   
C/S 客户端/服务端:通讯成本低,需要安装客户端,手动升级

8.DataReader和DataSet

两者最大的区别在于,DataReader使用时始终占用SqlConnection,在线操作数据库.任何对SqlConnection的操作都会引发DataReader的异常.因为DataReader每次只在内存中加载一条数据,所以占用的内存是很小的..因为DataReader的特殊性和高性能.所以DataReader是只进的.你读了第一条后就不能再去读取第一条了.

DataSet为离线操作数据,DataSet会将数据一次性读入内存,然后断开连接,这时其它操作就可以使用SqlConnection连接对象。因为DataSet将数据全部加载在内存中.所以比较消耗内存.但是确比DataReader要灵活.可以动态的添加行,列,数据.对数据库进行回传更新操作


9.在c#中using和new这两个关键字有什么意义?using 指令和语句 new 创建实例 new 隐藏基类中方法。
  using 引入名称空间或者使用非托管资源,相当于 try catch finally 使用完对象后自动执行实现IDisposable接口的类的Dispose方法释放对象资源
  new 新建实例或者修饰一个方法,表示此方法完全重写(即隐藏基类方法)

10.  虚函数  /  抽象函数  /  接口  /  静态函数
①虚函数:有实现体,实现多态性,子类可以重写也可以不重写直接拿来用。用Virtual 修饰,只能被单继承
②抽象函数:是一个类,有构造函数,用abstract修饰,没有实现体,非虚子类必须重写,有抽象方法一定是抽象类,但抽象类不一定有抽象方法。只能被单继承

③接口:不是类,没有构造函数,支持多态,用 Interface修饰,没有实现体,子类必须重写,支持多继承

④静态函数:用static修饰,第一次使用时被初始化,对于该类的所有对象来说,static成员变量只有一份,static方法中不可访问非static的成员。
 类定义前面放置关键字 sealed,可以将类声明为密封类。当一个类被声明为 sealed 时,它不能被继承。抽象类不能被声明为 sealed。
 
 11.重载与重写

重载:同一方法名,参数不同,或者参数个数不同,是多太的一种体现,或者是返回值的不同,或者是修饰符不同
重写:继承父类,对父类的方法重写
 override(重写)
   1、方法名、参数、返回值相同。
   2、子类方法不能缩小父类方法的访问权限。
   3、子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。
   4、存在于父类和子类之间。
   5、方法被定义为final不能被重写。
 overload(重载)
  1、参数类型、个数、顺序至少有一个不相同。 
  2、不能重载只有返回值不同的方法名。
  3、存在于父类和子类、同类中。

12.类和结构有以下几个基本的不同点:
类是引用类型,结构是值类型。
结构不支持继承。
结构不能声明默认的构造函数。
类的对象是存储在堆空间中,结构存储在栈中。堆空间大,但访问速度较慢,栈空间小,访问速度相对更快

13.值类型和引用类型

值类型(如 char、int 和 float)、枚举和结构。
引用类型包括类 (Class) 、String、接口、委托和数组。

声明一个值类型变量,编译器会在栈上分配一个空间存储该变量的值。

引用类型的实例分配在堆上,栈中存储 堆的内存分配地址

声明一个类时,先在栈上分配一个空间等待存储堆中的地址,new一个对象时才分配堆中的空间,并把地址赋值给栈。


14.反射(Reflection)
优点:
1、反射提高了程序的灵活性和扩展性。
2、降低耦合性,提高自适应能力。
3、它允许程序创建和控制任何类的对象,无需提前硬编码目标类。
缺点:
1、性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
2、使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。
反射(Reflection)有下列用途:
它允许在运行时查看特性(attribute)信息。
它允许审查集合中的各种类型,以及实例化这些类型。
它允许延迟绑定的方法和属性(property)。
它允许在运行时创建新类型,然后使用这些类型执行一些任务。
C# 高级教程   C# 特性(Attribute) | 菜鸟教程

15.泛型

当我们写一个带参的方法时,参数类型一般需要指定,Public void Test(int a)

但是类似于重方法载,会传入不同的参数类型时,我们可能会Public void Test(string b),Public void Test(datetime c),但是如果类型真的很多,这种方法显然不合适。

或者我们可以 Public void Test(Object a)  看起来一劳永逸,但实际上这个过程需要大量的装箱拆箱操作,如果访问量很大是十分消耗性能的。这个时候就可以用泛型   Public void Stack<T>

 CompareModels<in T>(T originalModel, T updatedModel)



16.匿名函数和匿名方法:
匿名函数不需要指定返回类型,它是从方法主体内的 return 语句推断的。

匿名方法是没有名称只有主体的方法。
匿名方法是通过使用 delegate 关键字创建委托实例来声明的
delegate void NumberChanger(int n);
...
NumberChanger nc = delegate(int x)
{
    Console.WriteLine("Anonymous Method: {0}", x);
};
C# 匿名方法 | 菜鸟教程

17.多线程和线程锁:

几张图看懂进程、线程和锁_进程锁和线程锁-CSDN博客
线程是轻量级进程
线程生命周期开始于 System.Threading.Thread 类的对象被创建时,结束于线程被终止或完成执行时
未启动状态:当线程实例被创建但 Start 方法未被调用时的状况。
就绪状态:当线程准备好运行并等待 CPU 周期时的状况。
不可运行状态:下面的几种情况下线程是不可运行的:
已经调用 Sleep 方法
已经调用 Wait 方法
通过 I/O 操作阻塞
死亡状态:当线程已完成执行或已中止时的状况。

进程中第一个被执行的线程称为主线程。

锁和死锁
这个是在多线程中用到,为了线程安全来使用线程锁控制资源的利用和释放,比如最直观的售票系统,同一张票只能在一个窗口卖,且剩余票不能是负数,否则就是线程不安全得
为了防止这种情况发生 加入了线程锁,但是使用不当,比如一个进程占用了一个资源,但是又去请求新的资源,但是新的资源被其他进程占用,他又没有释放当前资源,这样下一个进程请求该资源就会造成堵塞,也就是死锁,为了防止这种情况发生
加锁顺序(线程按照一定的顺序加锁)
加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)
死锁检测

18.IEnumberable和IQueryable和Tolist()

IEnumberable接口成为迭代器,就一个GetEnumberator()方法;它返回的是一IEnumberator对象这是一个可以循环访问集合的对象,IEnumberator是一个集合访问器。支持foreach语句,IEnumberator定义了Current属性,MoveNext和Reset两个方法;Current用来获取集合中的项,MoveNext方法只是将游标内部位置向前移动(就是移到下一个元素)

IQueryable继承IEnumberable接口,两者都是延时执行

IEnumerable<T> 泛型类在调用自己的SKip 和 Take 等扩展方法之前数据就已经加载在本地内存里了,实际使用时会在内存中执行后续方法获取结果,比较消耗内存,且会一直和数据库保持连接

而IQueryable<T> 是将Skip ,take 这些方法表达式翻译成T-SQL语句之后再向SQL服务器发送命令,它并不是把所有数据都加载到内存里来才进行条件过滤。但仍和数据库保持连接

Tolist()会立即执行,把结果加载到内存中,且和数据库断开连接。
 

19.viewbag和viewdata
ViewData和ViewBag一般用于View和Controller间传值,
ViewData是key值读取对应的value,ViewData["Name"] = "蝈蝈";
ViewBag是动态类型,使用时直接通过属性赋值即可,ViewBag.Message = "Your application description page.";

ViewData和ViewBag只在当前Action中有效,等同于View

ViewData和ViewBag中的值可以互相访问

20.消息队列

消息队列比作是一个存放消息的容器,当我们需要使用消息的时候可以取出消息供自己使用。

消息队列是分布式系统中重要的组件,使用消息队列主要是为了通过异步处理提高系统性能和削峰、降低系统耦合性。目前使用较多的消息队列有ActiveMQ,RabbitMQ,Kafka,RocketMQ

队列 Queue 是一种先进先出的数据结构,所以消费消息时也是按照顺序来消费的

消息队列最常用的是发布-订阅模式,还有点对点订阅模式(一个消息只有一个消费者)

使用消息队列进行异步处理之后,需要适当修改业务流程进行配合,比如用户在提交订单之后,订单数据写入消息队列,不能立即返回用户订单提交成功,需要在消息队列的订单消费者进程真正处理完该订单之后,甚至出库后,再通过电子邮件或短信通知用户订单成功。最常见的订票系统。

使用消息队列需要注意

①.保证消息的可靠性传输(如何处理消息丢失的问题)   消息队列的面试题4_php 队列面试题-CSDN博客

②.如何保证消息的顺序性?  消息队列的面试题5_c# 对列使用面试-CSDN博客

20.同步和异步

同步异步 指的是在客户端

同步意味着 客户端提出了一个请求以后,在回应之前只能等待

例子:你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。

异步意味着 客户端提出一个请求以后,还可以继续提其他请求

例子:书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。

阻塞非阻塞 指的是服务器端

阻塞意味着 服务器接受一个请求后,在返回结果以前不能接受其他请求

非阻塞意味着 服务器接受一个请求后,尽管没有返回结果,还是可以继续接受其他请求

21.构造函数和析构函数

析构函数:对象所在的函数已调用完毕时,系统自动执行析构函数。特别的一个类可以有多个构造函数,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。

析构函数:是一种特殊的方法。用于在撤销对象前,完成一些清理工作,比如:释放内存等。  但是一般GC(垃圾回收机制帮我们做掉了)

22.IIS和 IIS Express

IIS是一个系统服务,IIS Express则只是一个临时进程。

IIS需要我们安装,可以手动部署发布的应用程序,也可以直接运行程序会默认设置在IIS的Default Web Site中。有可视化界面

IIS Express集成在了VS中,用于调试,没有可视化界面,有配置文件。

23.枚举

枚举是一组命名整型常量。枚举类型是使用 enum 关键字声明的。

枚举是值类型。枚举类型保存到数据库中保存的是 在枚举中的位置

Enum.GetName(typeof(融资方系别), type); 获取原来的值

24.DataTable和DataSet

DataSet当成内存中的数据库,DataSet是不依赖于数据库的独立数据集合。所谓独立,就是说,即使断开数据链路,或者关闭数据库,DataSet依然是可用的,DataSet在内部是用XML来描述数据的,DataSet中可能有多个DataTable

DataTable是临时保存数据的网格虚拟表(表示内存中数据的一个表)

25. Skip(跳过) Take(获取) (C#里面集合的扩展方法,常用作分页)

var list = new  List<int>();

//比如 list里面是 1,2,3,4,5,6,7,8,9,10

var result = list.Skip(2);  //返回值就是 3,4,5,6,7,8,9,10;

var result = list.Take(2);  //返回值就是 1,2

//搭配使用,一般用来分页

var result = list.Skip(2).Take(2); //返回值 3,4

26.对比数组(Array)/集合(Set)/列表(List)
1、存储内容比较: Array 数组可以包含基本类型和对象类型, ArrayList 却只能包含对象类型。 Array 数组在存放的时候一定是同种类型的元素。ArrayList 就不一定了 。集合Set的对象都是不重复的,而且是无序的。

2、空间大小比较: Array 数组的空间大小是固定的,所以需要事前确定合适的空间大小。 ArrayList 的空间是动态增长的,而且,每次添加新的元素的时候都会检查内部数组的空间是否足够。

3.方法上的比较: ArrayList 方法上比 Array 更多样化,比如添加全部 addAll()、删除全部 removeAll()、返回迭代器 iterator() 等。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值