C#高级开发 线上面试题20240711

avatar
作者
筋斗云
阅读量:6

1.事件与委托什么关系,委托与lamda表达式是什么关系?

委托(Delegate) 是一种类型,它定义了方法的类型,使得可以将方法作为参数进行传递。委托是引用类型,它封装了一个或多个方法。委托的实例可以像调用方法一样被调用,而实际上它调用的是它所封装的方法。
事件(Events) 是一种特殊的多播委托,它用于在类之间提供通信。事件使得一个类(发布者)能够在某个重要事情发生时通知其他类(订阅者)。事件是对委托的封装,它增加了额外的访问限制(如使用+=和-=操作符来添加和移除事件处理程序),以确保委托列表的安全性。
事件是基于委托的,它利用委托来封装事件处理方法的列表,并提供了一种安全和类型安全的方式来注册和注销这些处理方法。
Lambda表达式 是一种简洁的编写匿名方法的方式。Lambda表达式可以转换成委托类型的实例,因为它们提供了一种快速定义委托实例的方法,而无需显式地声明一个方法。
Lambda表达式的基本语法是:(参数列表) => 表达式体 或 (参数列表) { 方法体 }。Lambda表达式可以赋值给委托类型的变量,这使得在需要委托实例的地方,可以使用Lambda表达式来快速定义所需的逻辑。
因此,委托与Lambda表达式的关系是Lambda表达式可以被用来创建委托的实例。这种关系使得在需要委托但不想显式定义整个方法时,能够使用Lambda表达式来快速编写和传递代码块。
事件是基于委托的,用于在类之间提供通信;而Lambda表达式提供了一种快速定义委托实例的方法,使得在需要委托但不想显式定义方法时,可以方便地编写和传递代码块。这三者共同构成了C#中处理回调和事件驱动编程的强大工具。


2.线程池都有哪些状态?线程有哪些状态?怎么防止死锁?


线程池并没有直接暴露给开发者一个明确的状态集合,因为线程池的设计目的是为了管理线程的生命周期和分配任务,而不是让开发者直接查询其内部状态。然而,可以从线程池的行为和功能中理解其“状态”的隐含含义:
未初始化:在第一次将任务排入线程池之前,线程池并未被创建。当第一次调用如ThreadPool.QueueUserWorkItem等方法时,线程池会被初始化。
空闲状态:线程池中没有任务执行,所有线程都处于空闲状态,等待任务的到来。
运行中:一旦线程池被初始化,它就会持续运行,接受并管理线程以执行任务。线程池中的线程会根据需要被创建和销毁,以维护一定的线程数量。
等待状态:线程池中的所有线程都处于忙碌状态,新来的任务需要排队等待,直到有线程可用。
受限状态如满载:线程池中的线程数量受到系统资源(如内存、CPU)和配置(如通过ThreadPool.SetMaxThreads设置的最大线程数)的限制。当达到这些限制时,无法接受更多的任务,需要等待当前任务完成释放线程。新的任务可能会被延迟执行,直到有线程变得可用。
线程的状态
虽然C#的System.Threading.Thread类没有直接提供一个枚举来表示所有线程状态,但可以根据线程的行为和生命周期识别出几种状态:
未启动(Unstarted):线程实例已被创建但尚未调用Start方法。
就绪(Ready):线程已准备好运行,但尚未被CPU调度。
运行(Running):线程正在执行其方法体中的代码。
阻塞(Blocked):线程因等待某个条件(如I/O操作、锁、睡眠等)而暂停执行。
等待(Waiting):线程正在等待某个事件(如Thread.Sleep、Monitor.Wait等)。
终止(Terminated):线程已完成执行或由于异常而终止。
防止死锁
死锁是指两个或多个线程在执行过程中,因争夺资源而造成的一种相互等待的现象,若无外力作用,这些线程都将无法向前推进。防止死锁的策略包括:
避免多个锁的顺序依赖:确保所有线程以相同的顺序获取锁。
使用超时:在尝试获取锁时使用超时机制,如果线程不能在指定时间内获取锁,则释放已获得的锁并稍后重试。
减少锁的粒度:尽量只锁定必要的资源,减少锁之间的依赖。
避免嵌套锁:尽可能避免在一个锁内部再获取另一个锁。
使用lock语句:lock语句是获取和释放锁的一种便捷方式,它确保了即使在发生异常时也能正确释放锁。
检测和恢复:虽然实现起来较为复杂,但可以通过检测死锁并采取相应的恢复措施来避免死锁的影响。
C#的线程池并没有直接的状态集合,而线程的状态可以通过其行为和生命周期来识别。防止死锁则需要开发者在设计和实现多线程程序时采取一系列的策略和措施。


3.DataReader和DataSet有什么区别?


DataReader和DataSet都是用于处理数据的类,但它们在设计、功能和使用场景上存在显著的区别。以下是它们之间的主要区别:
1. 数据访问方式
DataReader:DataReader是一种轻量级的、只进只读的数据流,用于从数据库中检索数据。它一次只能读取一行数据,并且在读取数据时,它是基于流的,不会将整个结果集加载到内存中。这使得DataReader在处理大型数据集时更加高效,因为它减少了内存的使用。然而,由于DataReader是只进只读的,所以无法进行数据的修改。
DataSet:DataSet是一个内存中的数据容器,可以存储多个表格以及它们之间的关系。它不仅可以从数据库中检索数据,还可以从XML文件等多种数据源中填充数据。DataSet提供了对数据的缓存和操作功能,可以对数据进行增删改查等操作。DataSet可以在离线状态下进行操作,即在从数据源中获取数据后,可以断开与数据源的连接,对数据进行处理,然后再将修改后的数据保存回数据源。
2. 内存占用与性能
DataReader:由于DataReader是按需读取数据的,所以它占用的内存相对较少ÿ

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!