C#.NET 面试题 初级篇(一)
更新: 2023-06-29 18:26:31 字数: 0 字 时长: 0 分钟
浅谈 C#中的深拷贝(DeepCopy)与浅拷贝(MemberwiseClone)
深拷贝:指的是拷贝一个对象时,不仅仅把对象的引用进行复制,还把该对象引用的值也一起拷贝。这样进行深拷贝后的拷贝对象就和源对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。比如一个黄狗叫大黄,使用克隆术克隆另外一个黄狗叫小黄,这样大黄和小黄就相对独立了,他们不互相影响。在 .NET 中 int,double 以及结构体和枚举等。
浅拷贝:指的是拷贝一个对象时,仅仅拷贝对象的引用进行拷贝,但是拷贝对象和源对象还是引用同一份实体。此时,其中一个对象的改变都会影响到另一个对象。就像一个人改名了一样,他还是这个人,只不过名字变了而已。
throw 与 throw e 的区别?应该用哪一个?
引发异常后,堆栈携带的部分信息就是堆栈跟踪。堆栈跟踪是方法调用层次结构的列表,该列表以引发异常的方法开始并以捕获异常的方法结束。如果通过在 throw 语句中指定异常来重新引发异常(也就是使用 throw ex),则堆栈跟踪将从当前方法重新启动,并且引发该异常的原始方法与当前方法之间的方法调用列表将丢失。要使原始堆栈跟踪信息与该异常保持一致,请使用 throw 语句而不指定该异常。
out 和 ref 有什么区别?
1、ref 参数必须初始化,out 不必。
2、因为 ref 需要初始化,所以 ref 可以在函数内部使用,而 out 未必初始化,所以不能在函数内部使用。
3、ref 参数已初始化,所以在函数内部不一定需要改变值,out 未必初始化,所以在结束函数前需要改变其值。
const 和 readonly 有什么区别?
1、初始化位置不同。const 必须在声明的同时赋值;readonly 即可以在声明处赋值,也可以在静态构造方法(必须是静态构造方法,普通构造方法不行)里赋值。
2、修饰对象不同。const 即可以修饰类的字段,也可以修饰局部变量;readonly 只能修饰类的字段。
3、const 是编译时常量,在编译时确定该值;readonly 是运行时常量,在运行时确定该值。
4、const 默认是静态的;而 readonly 如果设置成静态需要显示声明。
5、修饰引用类型时不同,const 只能修饰 string 或值为 null 的其他引用类型;readonly 可以是任何类型。
as 和 is 的区别?
as 在转换的同时判断兼容性,如果无法进行转换,返回位 null(没有产生新的对象),as 转换是否成功判断的依据是是否为 null, is 只是做类型兼容性判断,并不执行真正的类型转换,返回 true 或 false,对象为 null 也会返回 false。
as 比 is 效率更高,as 只需要做一次类型兼容检查。
HashMap 和 Hashtable 区别?
HashMap 是 Hashtable 的轻量级实现,非线程安全的实现他们都实现了 map 接口,主要区别是 HashMap 键值可以为空 null,效率可以高于 Hashtable。
params 有什么含义?有何用途?
params 关键字在方法成员的参数列表中使用,为该方法提供了参数个数可变,它在只能出现一次并且不能在其后再有参数定义,之前可以。
String 和 StringBuilder 的区别?
1、String 对象时恒定不变的,StringBuilder 对象表示的字符串是可变的。StringBuilder 是 .NET 提供的动态创建 String 的高效方式,以克服 String 对象恒定性带来的性能影响。
2、对于简单的字符串连接操作,在性能上 StringBuilder 并不一定总是优于 String。
因为 StringBuilder 对象创建代价较大,在字符串目标连接较少的情况下,过度滥用 StringBuilder 会导致性能的浪费,只有大量的或者无法预知次数的字符串操作,才考虑 StringBuilder 来实现。
事实上,一般连接次数设置 100 次以内,根本看不出两者的性能差别。
3、当修改字符串信息时,此时不许创建对象,可以使用 StringBuilder 对象。
String 对象是不可改变的。每次使用 System.String 类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间。
聚集索引和非聚集索引的区别?
1、聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个。
2、聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续。
3、聚集索引:物理存储按照索引排序;聚集索引是一种索引组织形式,索引的键值逻辑顺序决定了表数据行的物理存储顺序。
4、非聚集索引:物理存储不按照索引排序;非聚集索引则就是普通索引了,仅仅只是对数据列创建响应的索引,不影响整个表的物理存储顺序。
5、索引是通过二叉树的数据结构来描述的,我们可以这么理解聚集索引:索引的叶节点就是数据节点,而非聚集索引的叶节点仍然是索引节点,只不过有一个指针指向对应的数据块。
值类型与引用类型的区别?
1、值类型的数据存放在内存的栈中,引用类型的数据存放在内存的堆中。
2、值类型存取速度快,引用类型存取速度慢。
3、值类型表示实际数据,引用类型表示指向存储在内存堆中的数据指针或引用。
4、值类型的变量直接存放实际的数据,而引用类型的变量存放的则是数据的地址即对象的引用。
5、值类型变量直接把变量的值保存在堆栈中,引用类型的变量把实际数据的地址保存在堆栈中,而数据保存在堆中。
.Net Core 中如何捕获全局异常?
1、自定义一个全局异常过滤器
2、自定义异常处理中间件,然后使用中间件
泛型的优点
1、代码复用
2、降低了耦合性
3、更好的可读性
4、更高的安全性, 降低了强制类型转换的必要性和运行时错误的可能性。
5、更好的性能,泛型集合类型通常能更好地存储和操作值类型,因为无需对值类型进行装箱。
重载和重写的作用和区别
重载是方法的名称相同。参数或参数类型不同,进行多次重载以适应不同的需要,重载(overload)是面向过程的概念。
override 是进行基类中函数的重写,override 是面向对象的概念。
什么是委托?事件是委托吗?
委托可以把一个方法作为参数代入另一个方法。
委托可以理解为指向一个函数的指针。
委托和事件没有可比性,因为委托是类型,事件是对象,事件的内部是用委托实现的。
在微软官方文档中提到,事件是一种特殊的多播委托,只能从声明它的类中进行调用。客户端代码通过提供对应在引发事件时调用的方法的引用来订阅事件。 这些方法通过事件访问器添加到委托的调用列表中,这也是我们可以使用+=去订阅事件的原因所在,而取消事件则和多播委托一致,使用-=的方式。
什么是装箱(boxing)和拆箱(unboxing)?
装箱:把值类型转换成引用类型。
拆箱:把引用类型转换成值类型。
抽象类和接口的区别?
1、抽象类中的方法可以是普通方法和和抽象方法,接口中只能是抽象方法;
2、抽象类中可以有构造方法,接口中没有构造方法;
3、抽象类中的抽象方法的访问修饰符可以是 public 和 protected,而接口中抽象方法的访问修饰符只能是 public abstract;
4、抽象类中可以有普通成员变量,而接口中的只能是常量 public static final;
5、抽象类中可以有静态方法,接口中不能包含静态方法;
6、抽象类中的成员变量的访问修饰符可以是任意,接口中的成员变量修饰符只能是 public;
7、一个类可以实现多个接口,但只能继承一个抽象类。
.Net Core 自带的依赖注入有哪几种
.Net Core 主要提供了三种依赖注入的方式:
1、AddTransient 瞬时模式:每次请求,都获取一个新的实例。即使同一个请求获取多次也会是不同的实例
2、AddScoped:每次请求,都获取一个新的实例。同一个请求获取多次会得到相同的实例
3、AddSingleton 单例模式:每次都获取同一个实例
权重:
AddSingleton => AddTransient => AddScoped
AddSingleton 的生命周期:
项目启动-项目关闭 相当于静态类 只会有一个
AddScoped 的生命周期:
请求开始-请求结束 在这次请求中获取的对象都是同一个
AddTransient 的生命周期:
请求获取-(GC 回收-主动释放) 每一次获取的对象都不是同一个
如何解决.net 中的内存泄漏问题?用到过哪些检测工具?
.Net 内存泄漏,更准确的说应该是对象超过生命周期而不能被 GC 回收。
常见的内存泄露有:
静态引用、控件不使用后未销毁、调用非托管资源而未释放、事件注册后未解除注册等
解决方案:
1、Dispose 的使用
如果使用的对象提供 Dispose 方法,那么当你使用完毕或在必要的地方(比如 Exception)调用该方法,特别是对非托管对象,一定要加以调 用,以达到防止泄露的目的。
2、using 的使用
using 除了引用 Dll 的功用外,还可以限制对象的适用范围,当超出这个界限后对象自动释放,比如 using 语句的用途定义一个范围,将在此范围之外释放一个或多个对象。
3、事件的卸载
这个不是必须的,推荐这样做。之前注册了的事件,关闭画面时应该手动注销,有利于 GC 回收资源。
4、API 的调用
一般的使用 API 了就意味着使用了非托管资源,需要根据情况手动释放所占资源,特别是在处理大对象时。
5、弱引用(WeakReference)
通常情况下,一个实例如果被其他实例引用了,那么他就不会被 GC 回收,而弱引用的意思是,如果一个实例没有被其他实例引用(真实引用),而仅仅是被弱引 用,那么他就会被 GC 回收。
诊断工具:
1、大多使用 windows 自带的 perfmon.msc
2、用过的工具里面 CLRProfiler 和 dotTrace 还行,windbg 也还行
不过坦白的说,准确定位比较费劲,最好还是按常规的该 Dispose 的加 Dispose,也可以加 GC.Collect
Redis 和 Mongodb 以及 Memcached 的优缺点
Redis 优势:
速度快,存储在内存中,时间复杂度为 O(1)
支持丰富的数据类型:(string,list,set,sorted set,hash)支持多种数据结构,如 string(字符串)、 list(双向链表)、dict(hash 表)、set(集合)、zset(排序 set)、hyperloglog(基数估算)
支持事务,操作都是原子性.所谓原子性就是对数据的更改要么全成功要么全失败
丰富的特性可用于缓存,消息,按 key 设置过期时间,过期后会自动删除
支持持久化操作,可以进行 aof 及 rdb 数据持久化到硬盘,从而进行数据备份或数据恢复等操作,较好的防止数据丢失的手段
支持通过 Replication 进行数据复制,通过 master-slave 机制,可以实时进行数据的同步复制
Redis 缺点:
Redis 只能使用单线程,性能受限于 cpu 性能
支持简单的事务需求,不成熟,不支持回滚
Redis 在 string 类型上会小号较多内存,可以使用 dict 压缩存储以降低内存好用
Mongodb 优势:
MongoDB 却是一个“存储数据”的系统,增删改查可以添加很多条件,就像 SQL 数据库一样灵活
丰富的数据表达、索引;最类似于关系数据库,支持丰富的查询语言
适合大数据量存储,依赖系统虚拟内存管理,采用镜像文件存储;内存占有率比较高
支持 master-slave,replicaset(内部采用 paxos 选举算法,自动故障恢复),auto sharding 机制,对客户端屏蔽了故障转移和切分机制
海量数据的访问效率提升<更高的写负载,MongoDB 拥有更高的插入速度。
模式自由 :可以把不同结构的文档存储在同一个数据库里
面向集合的存储:适合存储 JSON 风格文件的形式
完整的索引支持:对任何属性可索引
复制和高可用性:支持服务器之间的数据复制,支持主-从模式及服务器之间的相互复制。复制的主要目的是提供冗余及自动故障转移
自动分片:支持云级别的伸缩性:自动分片功能支持水平的数据库集群,可动态添加额外的机器
丰富的查询:支持丰富的查询表达方式,查询指令使用 JSON 形式的标记,可轻易查询文档中的内嵌的对象及数组
快速就地更新:查询优化器会分析查询表达式,并生成一个高效的查询计划
高效的传统存储方式:支持二进制数据及大型对象(如照片或图片)
Mongodb 缺点:
不支持事务。
Mongodb 占用空间过大
Mongodb 没有成熟的维护工具
Memcached 优势:
Memcached 可以利用多核优势,单实例吞吐量极高,适用于最大程度扛量
支持直接配置为 session handle。
Memecached 把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小
Memcached 缺点:
数据类型比较单一
无法实现持久化,数据不能备份,只能用于缓存使用且重启后数据丢失
无法进行数据通过
需要注重 value 的设计