c#面试题

如下为自己认为比较好的面试题集合,随时更新

目录

c#类题目

数据库类题目

算法类题目

c#类题目

.NET常见面试题 - 九八八五 - 博客园 (cnblogs.com)

 Q:什么是 CTS、CLS 和CLR

A: 公共语言运行库(CLR)是一个CLI 的一个实现,包含了.NET 运行引擎和符合 CLI 的类库。 
通用类型系统(CTS)包含在微软公司提交的 CLI 规范,定义了一个可以在 CLR 上运行的类型规范。 
公共语言规范是 CTS的一个子集,定义了所有面向.NET 的程序所需要符合的最小规范集。

Q:JIT是如何工作的 
JIT 引擎在编译中间代码之前,会寻找方法的本机机器代码缓存并且判断其是否可用,如果可用则直接加载,如果不可用,JIT 引擎会查找类型中的方法存根,找到该中间代码并且进行编译

关于JIT与CIL的学习:C#/.NET JIT和IL(MSIL或CIL)实现跨平台 (biancheng.net)

Q:怎么把程序集放入 GAC 中   (未使用过,有待实践)
GAC是一个具有特定目录结构的文件夹,所有强签名的程序集都可以被放入GAC中。可以通过.NET Framework自带的assembly viewer来简单地拖动添加一个程序集到 GAC 中,也可以利用诸如 gacutil.exe等工具使用命令行来添加。总之,任何方法归根结底,都是根据 GAC 的规范和程序集本身的特性,在GAC目录下建立相应的子目录结构。

Q:值类型和引用类型的区别 
所有继承自System.ValueType 的类型是值类型,而其他类型都是引用类型。值类型的赋值会产生一个新的数据副本,所以每个值类型都拥有一个数据副本,而引用类型的赋值则是赋值引用。值类型的对象分配在堆栈上,而引用类型的对象分配在堆上。当比较两个值类型时,进行的是内容比较,而比较两个引用类型时,进行的是引用比较。

实际例子:当你存在一个list时,你在循环时修改某个值,此list集合其实也在被修改

当我们不想去修改原有的集合时,如何去做呢?

扩展1:一般可以序列化,反序列化一下这个集合或者数据,然后用一个新的变量去接收反序列化的值即可。

扩展2:值类型装箱、拆箱

1、装箱:就是将值类型的数据打包到引用类型的实例中( 比如将int类型的值1赋给object对象obj)

int  i=1;  
object obj=(object)i;  

 装箱时到底发生了什么:

1)、在托管堆中分配内存。分配的内存量是值类型各字段所需的内存量,还要加上托管堆所有对象都有的两个额外成员(类型对象指针和同步块索引)所需的内存量

2)、值类型的字段复制到新分配的堆内存

3)、返回对象地址,现在该地址是对象引用;值类型成了引用类型

2、拆箱:就是从引用数据中提取值类型(比如将object对象obj的值赋给int类型的变量i)

object obj=”1”;  
int i=(int)obj;  

拆箱不是装箱过程倒过来,拆箱的代价要比装箱低的多,拆箱是获取指针的过程,该指针指向包含在一个对象中的原始值类型。

拆箱后将堆中的字段包含的值复制栈的值类型实例中。

3、值类型变为引用类型不一定要装箱,例如:

string str = "joye.net" + 26;   //需要将26装箱为string类型
string str1 = "joye.net" + 26.ToString(); //tostring后不需要装箱。通过反编译可以知道 ToString是被重写的方法。
// return String.Format("{0}",x);  所以不涉及到装箱

案例题目

如下代码,分析最终输出结果,及其为何会输出此结果

class StartProgram
{
   void Start()
   {
      double pointX1 = 100.1;
      var point1 = new Point();
      point1.PointX = 200.1;
      InitialPoint(pointX1, point1);
      Console.WriteLine(string.Format("pointX1:{0}", pointX1));
      Console.WriteLine(string.Format("point1.PointX:{0}", point1.PointX));
      Console.ReadKey();
    }
    void InitialPoint(double pointX2, Point point2)
    {
       pointX2 = 300.1;
       point2.PointX = pointX2;
point2=null; } }

  

 输出结果:

Output:pointX1:100.1
point1.PointX:300.1 


分析:

当程序中进行参数传递的时候,也是默认按值传递,值类型复制数据本身,形成独立的数据块,引用类型复制引用,指向同一实例。所以进入InitialPoint中的point2,在栈上是一个新的地址,只是与point1指向了同一地址。point2置为Null,只是把引用修改了,但是修改pointx时,是修改了内部的值 传递引用后之前我们修改的值是对象的值,也就是堆上的数据,但是之后我们设置为null,是将引用本身设置为null,而不是将堆上的对象设置为null


此题目可以进行自由变化,例如
class StartProgram
{
   void Start()
   { 
      var point1 = new Point();
      point1.PointX = 200.1;
      InitialPoint(point1.PointX, point1);
      Console.WriteLine(string.Format("point1.PointX:{0}", point1.PointX));
      Console.ReadKey();
    }
    void InitialPoint(double pointX2, Point point2)
    {
       point2.PointX = pointX2;
       pointX2 = 300.1;
      point2=null;
    }
 }

等等,可以自己上手试一下

同时由此题可以扩展

1.c#中的参数类型也是分为:传递值和传递引用的

2.对于传参方式中的ref和out都是传递的引用

Q: .NET中GC 的运行机制 
垃圾回收是指收集释放托管堆上不再被使用的对象内存。其过程基本包括:通过算法找到不再被使用的对象、移动对象使所有仍被使用的对象紧靠托管堆的一边和调整各个状态变量。 垃圾回收的运行成本较高,对性能的影响较大。程序员在编写.NET 代码时,应该避免不必要的内存分配,尽量减少或避免使用 GC.Collect来执行垃圾回收。

Q: 简述 C#中重写、重载和隐藏的概念 
重写是指用 override 关键字重新实现基类中的虚方法,在运行的过程中,无论通过哪个类型的引用,真正对象类型的方法将被调用。隐藏是指用 new关键字重新实现基类中的方法,在运行的过程中通过引用的类型判断应该调用哪个类型的方法。重载是指多个方法共享同一个名字并且拥有相同的返回值,但是却可以拥有不同的参数列表。

Q:接口是否可以继承接口?抽象类是否可以实现接口?抽象类是否可以继承实体类?

答:接口是可以继承接口的,抽象类是可以实现接口的,抽象类可以继承实体类,但是有个条件,条件是,实体类必须要有明确的构造函数。

 Q: GET请求和 POST 请求有何区别

可以先表面入手回答此问题:

表面上:1.Get参数拼接字URL上,POST放在request body中。同时也表明了Get请求暴露了参数,不能传递敏感信息

2 GET产生的URL可以被浏览器记住,回退不会产生新的请求,POST请求,回退时,会产生新的请求

3.Get请求有长度限制,POST没有参数的长度限制

4.GET只接受ASCII字符,而POST没有限制

实质上:

Get和post没有什么区别,get和post都是HTTP协议中的两种发送请求的方法。HTTP的底层是TCP/IP。所以GET和POST的底层也是TCP/IP,也就是说,GET/POST都是TCP链接。GET和POST能做的事情是一样一样的。你要给GET加上request body,给POST带上url参数,技术上是完全行的通的。 

深层次:

GET和POST还有一个重大区别,简单的说:

GET产生一个TCP数据包;POST产生两个TCP数据包。

详细答案参考:https://www.cnblogs.com/logsharing/p/8448446.html

 Q:页面的生命周期

参考我之前的博客:c# 关于页面生命周期

 Q:sql参数化

-----待定

123

Q: 请简要叙述数据库连接池的机制

 Q:如何深克隆一个对象?

首先,确定此对象可以被序列化,即实现了Serializable接口,然后通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。

Q:  Session有哪几种存储方式,之间有何区别,如何进行设置

首先,Session分为客户端Session和服务端Session两种类型

详细学习见此博客  https://www.cnblogs.com/zhangkai2237/archive/2012/03/22/2410890.html

扩展1:sessionState mode="Custom" (Custom自定义模式)。
分布式项目通常部署到不同的服务器中,而传统的session只存储到本地服务器,并不能达到session跨域使用,以此程序员们就想到一种方式,达到session共享,现在达到session共享简单的方法就是将session放入到redis缓存中
  参见具体博客:https://www.cnblogs.com/5ishare/p/7507980.html (此博客未实践,但是知识点可以参考)

扩展2:webapi获取不到session问题解决 参见具体博客:https://www.cnblogs.com/kekelele/p/15587311.html

 Q:ADO.NET的5个常用对象以及功能

必须手写掌握的代码(既包含拿电脑写,拿笔写)

  1. 手写三层架构
  2. 手写冒泡排序
  3. 手写AJAX:XMLHttpRequest
  4. 手写增删改查、SQLHelper

 

 

 

 

 

数据库

Q:从数据库读取记录,你可能用到的方法有

ExecuteNonQuery 执行的是 增加 修改于删除
ExecuteScalar 执行的是 返回int类型的查询存在
Fill是用来查询填充 Adaputer的集合类
ExecuteReade用用来返回 DateReader查询结果集

所以,可能用到的方法有:ExecuteScalar,Fill ,ExcutreReader

Q:什么是事务?什么是锁?

答:事务是指一个工作单元,它包含了一组数据操作命令,并且所有的命令作为一个整体一起向系统提交或撤消请求操作,即这组命令要么都执行,要么都不执行。

  锁是在多用户环境中对数据的访问的限制。SqlServer自动锁定特定记录、字段或文件,防止用户访问,以维护数据安全或防止并发数据操作问题,锁可以保证事务的完整性和并发性。

 

 

 

 

算法类

Q:一列数的规则如下: 1、1、2、3、5、8、13、21、34...... 求第30位数是多少,用递归算法实现

答:

 
public class MainClass 
{
     

    public static void Main()
    {
        Console.WriteLine(Foo(30));
          
    }

    public static int Foo(int i)
    {

        if (i <= 0) return 0;
        else if(i > 0 && i <= 2) return 1;
        else return Foo(i - 1) + Foo(i - 2);

    }

}
 


Q:请编写一个冒泡排序

 
public void Bubble(int[] nums)
{

  for (int i = 0; i < nums.Length - 1; i++)
  {
    for (int j = 0; j < nums.Length-1-i; j++)
    {
        if (nums[j] > nums[j + 1])
        {
            int temp = nums[j];
            nums[j] = nums[j + 1];
            nums[j + 1] = temp;
        }
    }
  }

}
 

 Q:请对以下数据进行由小到大排序   11,3,7,0,12,34,9,45,27,56,89,18,23,66

快速排序的实现

        public int sortUnit(int[] array, int low, int high)
        {
            int key = array[low];
            while (low < high)
            {
                /*从后向前搜索比key小的值*/
                while (array[high] >= key && high > low)
                    --high;
                /*比key小的放左边*/
                array[low] = array[high];
                /*从前向后搜索比key大的值,比key大的放右边*/
                while (array[low] <= key && high > low)
                    ++low;
                /*比key大的放右边*/
                array[high] = array[low];
            }
            /*左边都比key小,右边都比key大。//将key放在游标当前位置。//此时low等于high */
            array[low] = key;
            foreach (int i in array)
            {
                Console.Write("{0}\t", i);
            }
            Console.WriteLine();
            return high;

        }
        public  void Quick(int[] array, int low, int high)
        {
            if (low >= high)
                return;
            /*完成一次单元排序*/
            int index = sortUnit(array, low, high);
            /*对左边单元进行排序*/
            Quick(array, low, index - 1);
            /*对右边单元进行排序*/
            Quick(array, index + 1, high);
        }
View Code

 NET CORE

优点:按需加载,高效

Q:有哪些基础的是已经注入了(例如log),有哪些是需要自己手动配置的(例如session)?

Q: .net core 中的configservices 和config分别有什么作用?

Q:NETCORE 为什么可以用控制台托管?

因为netcore内置了Kestrel(注:有了kestrel才能真正实现跨平台)

视频学习

NET5零基础完整实战教程详解
地址:https://study.163.com/course/introduction.htm?courseId=1211262801&utm_campaign=share&utm_medium=androidShare&utm_content=courseIntro&utm_u=1450121140&utm_source=weixin

NET架构师训练营

https://study.163.com/course/introduction.htm?courseId=1210611811&utm_campaign=share&utm_medium=androidShare&utm_content=courseIntro&utm_u=1450121140&utm_source=weixin

ASP.NET Core 学习视频教程(Blog.Core)

https://www.bilibili.com/video/BV1D4411c7s8?p=1&share_medium=android&share_plat=android&share_session_id=fe458302-fa37-4bc3-8f5c-5585a375cab8&share_source=WEIXIN&share_tag=s_i&timestamp=1637823051&unique_k=Zs6uvvo

【编程入门】(完结)深入浅出ASP.NET Core 入门新手教程合集

https://www.bilibili.com/video/BV1wb411W7aB?p=1&share_medium=android&share_plat=android&share_session_id=4819a5a8-5bb0-4bc8-905c-c1f0c0bd7ee9&share_source=WEIXIN&share_tag=s_i&timestamp=1637823074&unique_k=DtWcVgc

原文地址:https://www.cnblogs.com/kekelele/p/15594541.html