C# 常见面试问题汇总

1、c#垃圾回收机制

    从以下方面入手展开:  1、压缩合并算法   2、代的机制  3、GC调用终结器 Garbage Collector

   . NET采用了和Java类似的方法由CLR(Common Language Runtime)来管理 

     .NET的GC机制有这样两个问题:

  首先,GC并不是能释放所有的资源。它不能自动释放非托管资源。

  第二,GC并不是实时性的,这将会造成系统性能上的瓶颈和不确定性。

  GC并不是实时性的,这会造成系统性能上的瓶颈和不确定性。所以有了IDisposable接口,IDisposable接口定义了Dispose方法,这个方法用来供程序员显式调用以释放非托管资源。使用using语句可以简化资源管理。

       具体详见:https://www.cnblogs.com/nele/p/5673215.html

2、委托和事件

     先说它的定义:委托的本质是类,类型安全的指针,然后从用途上考虑,事件是包装的委托,但事件不是委托。事件是由一个私有委托和add、remove 方法组成。

     事件、索引器、属性本质都是方法。接口只可以定义方法。所以接口也可以定义“事件、索引器、属性”,因为他们的本质也是add、remove 方法。

     委托是一种可以指向方法的数据类型,可以声明委托类型变量。

     声明委托的方式:delegate返回值类型   委托类型名(参数)

     比如delegate void MyDel(int n) 。C#中默认写了2中委托Action<>,Func<>,Action基本上都是void没有返回值,Func是有返回值的

    

 1 using System.Collections.Generic;
 2 using System.Linq;
 3 using System.Text;
 4 using System.Threading.Tasks;
 5 
 6 namespace TestConsole
 7 {
 8     delegate void MyDel();
 9     class Program
10     {
11 
12         static void Main(string[] args)
13         {
14             person p = new person();
15             p.QingZhu += ShowMsg;
16             p.age = 24;
17             Console.ReadKey();
18         }
19         static void ShowMsg()
20         {
21             Console.WriteLine("今年是你的本命年!恭喜你");
22         }
23     }
24     class person
25     {
26         private int Age;
27         public int age
28         {
29             get
30             {
31                 return age;
32             }
33             set
34             {
35                 if (value % 12 == 0)
36                 {
37                     if (QingZhu != null)
38                     {
39                         QingZhu();//执行事件
40                     }
41                 }
42             }
43         }
44         public event MyDel  QingZhu;
45     }
46 }
View Code
 1 using System;
 2 using System.Collections;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 
 8 namespace TestConsole
 9 {
10     delegate void MyDel();
11     class Program
12     {
13 
14         static void Main(string[] args)
15         {
16             person p = new person();
17             p.qingzhu += ShowMsg;
18             p.age = 24;
19             Console.ReadKey();
20         }
21         static void ShowMsg()
22         {
23             Console.WriteLine("今年是你的本命年!恭喜你");
24         }
25     }
26     class person
27     {
28         private int Age;
29         public int age
30         {
31             get
32             {
33                 return age;
34             }
35             set
36             {
37                 if (value % 12 == 0)
38                 {
39                     if (this.QingZhu != null)
40                     {
41                         this.QingZhu();//执行事件
42                     }
43                 }
44             }
45         }
46         private  MyDel  QingZhu;
47         public event MyDel qingzhu
48         {
49             add
50             {
51                 this.QingZhu += value;
52             }
53             remove
54             {
55                 this.QingZhu -= value;
56             }
57         }
58 
59     }
60 }
View Code

3、c#索引

    索引可以是字符串类型的,可以允许有多个索引参数,下面的方法我就可以定义多个参数。常见的Dictory<string,string>也是索引的一种。在IL中本质其实是Get_Item 方法(无参数)、Set_Item 方法(参数:value)。

 1 class MyIntIndex
 2     {
 3         private static string[] name = { "dandan", "chizi", "jianguo" };
 4         public string this[int index]
 5         {
 6             get
 7             {
 8                 string n = name[index];
 9                 return n;
10             }
11             set
12             {
13                 name[index] = value;
14             }
15         }
16     }
17 }
View Code

4、装箱和拆箱

    值类型和引用类型之间的转换。频繁装箱和拆箱会导致系统性能降低,可考虑用泛型。值类型赋值给object为装箱操作,值类型赋值给object拆箱(显示转换)。装什么类型拆箱就是什么类型,除非C#中convert.toInt32 等内置的这些方法可以强制拆箱。

5、泛型

   考得不多,但我们平常用的比较多。所以对泛型的一些东西需要了解,如泛型约束等。 

   泛型约束 public void GetEntity<T>() where T:class

    where T :struct //约束T必须为值类型
    where K : class //约束K必须为引用类型
    where V : IComparable //约束V必须是实现了IComparable接口
    where W : K //要求W必须是K类型,或者K类型的子类
    where X :class ,new () // 或者写出 new class() ;   X必须是引用类型,并且要有一个无参的构造函数(对于一个类型有多有约束,中间用逗号隔开)

6、c#如何调用c++ 的dll?为什么可以调用

     右击添加类中的“TypeLib中的MFC类”选项实现跨平台调用。添加好后会生成h文件和cpp文件

   tjdmwj2tjdmwj3tjdmwj4

   填写完后Function.h文件会报错,错误类型如下。这里需要在C++项目里面设置,让动态库受到公共语言运行时的支持。如下图所示:打开项目属性

   tjdmwj4tjdmwj5tjdmwj6

     C#和C++在vs中的语法类型都会编译成CTS(Common Type System通用数据类型)生成.net 中有CLS(Common Language Specification公共语言允规范) 并在IL代码中的CLR(Common Language Runtime 公共语言运行池)中运行。

     Int和Int32,string与String的区别,一个是C#代码中的类型,一个是IL中的CTS通用数据类型

7、托管资源和非托管资源

    问题:1、定义  2、如何释放

   托管资源是指由CLR管理分配和释放的资源。托管资源有GC释放,非托管资源由程序员自己释放,可以实现dispose接口。

   关于托管资源,就不用说了撒,像简单的int,string,float,DateTime等等,.net中超过80%的资源都是托管资源。

   非托管资源如何释放,.NET Framework 提供 Object.Finalize 方法,它允许对象在垃圾回收器回收该对象使用的内存时适当清理其非托管资源。

   值类型在栈内存中,方法结束自动释放,引用类型在堆内存中需要GC来回收

   

~MyClass()
{
  // Perform some cleanup operations here.
}
  该代码隐式翻译为下面的代码。
protected override void Finalize()
{
  try
  {
    // Perform some cleanup operations here.
  }
  finally
  {
    base.Finalize();
  }
}

 

在一个包含非托管资源的类中,关于资源释放的标准做法是:

(1) 继承IDisposable接口;

(2) 实现Dispose()方法,在其中释放托管资源和非托管资源,并将对象本身从垃圾回收器中移除(垃圾回收器不在回收此资源);

(3) 实现类析构函数,在其中释放非托管资源。

 

 1 PublicclassBaseResource:IDisposable
 2 {
 3   PrivateIntPtr handle; // 句柄,属于非托管资源
 4   PrivateComponet comp; // 组件,托管资源
 5   Privateboo isDisposed = false;// 是否已释放资源的标志
 6    PublicBaseResource()
 7    {
 8    }
 9    //实现接口方法
10    //由类的使用者,在外部显示调用,释放类资源
11    Publicvoid Dispose()
12    {
13      Dispose(true);// 释放托管和非托管资源
14      //将对象从垃圾回收器链表中移除,
15     // 从而在垃圾回收器工作时,只释放托管资源,而不执行此对象的析构函 
16 17     GC.SuppressFinalize(this);
18     }
19     //由垃圾回收器调用,释放非托管资源
20     ~BaseResource()
21      {
22       Dispose(false);// 释放非托管资源
23      }
24     //参数为true表示释放所有资源,只能由使用者调用
25     //参数为false表示释放非托管资源,只能由垃圾回收器自动调用
26    //如果子类有自己的非托管资源,可以重载这个函数,添加自己的非托管 
27     资源的释放
28    //但是要记住,重载此函数必须保证调用基类的版本,以保证基类的资源 
29     正常释放
30     Protected virtual void Dispose(booldisposing)
31    {
32      If(!this.disposed)// 如果资源未释放 这个判断主要用了防止对象被多 
33 34       释放
35     {
36      If(disposing)
37      {
38       Comp.Dispose();// 释放托管资源
39      }
40        closeHandle(handle);// 释放非托管资源
41        handle= IntPtr.Zero;
42       }
43       this.disposed=true;// 标识此对象已释放
44     }
45 }
View Code

8、MVC原理

   路由机制,我觉得此题,根据自己的理解回答即可,可深入回答  从view上请求到controller组织model,反映到view上.详细框架原理,可以查看:https://blog.csdn.net/jehuyang/article/details/100575686

9、MVC中,后台向前台页面传对象的方式

   强类型的模型绑定、ViewData、ViewBag 。其中ViewData是ViewDataDictory类型,而VieBag是dynamic类型. dynamic 可以动态给不同的类型。例如:dynamic p1=new Expandobject(); p1.Age=10; p1.Age="222";这样也不会报错。

10、MVC中过滤器

   Filter过滤器.AOP 面向切面编程。

   IAuthorizationFilter 一般检查用户是否有Action执行权限。在每个Action之前执行OnAuthorization方法。

   IActionFilter在每个Action之前执行OnActionExcuting方法,在每个Action执行完成后执行OnActionExecuted 方法. IAuthorizationFilter在IActionFilter执行之前执行,所以检查权限一般写在IAuthorizationFilter中的OnAuthorization方法中。

   IResultFilter在每个ActionResult的前后执行,一般很少用

   IExceptionFilter当每个Action有未处理的异常执行OnException 方法。MVC中可以使用Application_Error,但建议使用IExceptionFilter方法。

   定义的类可以在Global中Global.Filters.Filter.Add(new XXXFilter())添加使用。

11、c#扩展方法如何写?

    静态类+静态方法+this,例如下面代码:

class Program
    {
        static void Main(string[] args)
        {
            string str = "Hello World!";
            str.ShowMsg(str);
            Console.ReadKey();
        }
  }
    #region 扩展方法
    static class MyString
    {
        public static void ShowMsg(this string a, string msg)
        {
            Console.WriteLine(msg);
        }
    }
    #endregion 扩展方法

12、.NET Core Api 安全验证以及中间件 (本人没有了解过,代深入了解

     采用jwt,生成token验证,比如我们用来错误处理的中间件,可以定义其它功能的中间件。了解详细页面:https://www.cnblogs.com/savorboard/p/aspnetcore-authentication.html

13、设计模式(本人没有了解过,代深入了解)

     常用的设计模式:工厂、抽象工厂、代理、适配器、模板、策略、单例、观察者等,根据自己在项目中的使用情况,可以谈一谈。介绍链接:https://www.cnblogs.com/mq0036/p/8288099.html

14、单点登录

      单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。使用“单点登录”整合后,只需要登录一次就可以进入多个系统,而不需要重        新登录,这不仅仅带来了更好的用户体验,更重要的是降低了安全的风险和管理的消耗。介绍链接:https://www.cnblogs.com/yueshutong/p/9468035.html

15、聚集索引和非聚集索引

      聚集索引:也叫聚簇(cu)索引。数据行的物理顺序与列值(一般是主键的那一列)的逻辑顺序相同,一个表中只能拥有一个聚集索引。

      非聚集索引:该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同,一个表中可以拥有多个非聚集索引。

16、char,varchar、nvarchar区别   

char 

char是定长的,这个怎么说呢,比如你用char(10),当你输入6个字符时,它会用英文的空格给补全。当你输入的15个字符时,它会自动截取前10个字符。取值范围1-8000

优点:适合存储定长的数据,存储效率快

缺点:使用不当会造成存储空间的浪费
varchar

varchar可变长度的,存储的大小为输入数据的字节的实际长度,所输入的数据字符长度可以为0。取值范围0-8000

优点:适合存储不固定长度的数据,它可以识别出字节用于保存实际使用多大的长度。合理的利用的存储空间。

缺点:存储效率低

nvarchar

我们都知道英文字母占一个字节,汉字占两个字节,如果我们的数据中又有英文,又有汉字,这时nvarchar就该上场了,nvarchar无论是英文还是汉字都是用两个字节来表示。

优点:适合存储既有英文和汉字的数据

缺点:它最多能存储4000个字符,对英文存储上有些损失

17、数据库死锁产生的原因及解决办法(本人没有了解过,代深入了解)

      两个进程各自占有资源,然后它们都还想得到对方的资源,而自己不肯释放资源。我觉得死锁的活该,谁叫你那么贪婪。

18、有用过缓存吗?有用过redis吗?

     你若回答用过,面试官继续追问;你若回答没用过,他会觉得这都没有用过。

     缓存为了提高应用程序性能,因为请求数据库的次数少了。redis有很多特点:1、key-value   2、内存数据库,可以持久化到硬盘上  3、可以用作消息队列

19、IOC、依赖注入、容器

      IOC是一种思想,控制反转,反转的是对象的控制权,把生成对象的权利交到外部。比如在方法中要使用一个Student对象,有三种方法,1、用的时候,直接New一个对象  2、从方法参数中传入Student对象   3、从容器中获取一个Student对象

20、大文件上传与下载,如何考虑?比如说50G的大文件

      可以分段下载,webconfig中必须配置大小。具体没有研究过待研究       

21、Linq

22、AOP

    面向切面的编程。比如给每个Controller,添加日志功能,AOP是横向思维的一种体现。和问题10有重复

23、SOA、Webservice、WCF  (具体没有研究过待研究 )      

    问题:Webservice与WCF区别

    WCF是一个统一的框架,包括了remotting、Webservice,msmq,可以采用tcp和http等协议。也可以进行安全设置和验证。缺点:配置复杂

24、有研究过Docker吗

    Docker是一个平台,解决部署问题。需要理解Image(镜像)和Container的关系,了解运行机理

25、有研究过微服务吗

26、sql性能优化

      查看sql执行计划、拆库、拆表、优化语句等

27、你了解串口编程吗

     就是控制摄像头之类的设备编程,得了解计算机的基本原理

28、js字符串和数组相互转化

29、请设计一个递归算法

      比如5的阶乘,递归算法的一个要点是要设置结束条件,否则会栈溢出。

30、如何考虑做一个网站

31、线性表和链表的区别

32、谈谈你对js闭包的理解

33、多线程中的同步、异步、Task

     异步主要为了提升吞吐量,防止阻塞。Task主要提供了一个管理线程的接口,比如获取线程的结果、状态、取消线程的执行等

34、用过NoSql吗

    redis  、Memcached、MongoDB等

    redis 的优点: 

       1)  支持 string、list、set、geo 等复杂的数据结构。

       2)  高命中的数据运行时是在内存中,数据最终还是可以保存到磁盘中,这样服务器重启之后数据还在。

       3)  服务器是单线程的,来自所有客户端的所有命令都是串行执行的,因此不用担心并发修改(串行操作当然还是有并发问题)的问题,编程模型简单;

       4)  支持消息订阅/通知机制,可以用作消息队列;

       5)  Key、Value 最大长度允许 512M; 

     redis 的缺点: 

1)  Redis 是单线程的,因此单个 Redis 实例只能使用一个 CPU 核,不能充分发挥服务器的性能。可以在一台服务器上运行多个 Redis 实例,不同实例监听不同端口,再互相组成集群。

2)  做缓存性能不如 Memcached; 

    Memcached 的优点:
              1) 多线程,可以充分利用 CPU 多核的性能; 2) 做缓存性能最高;

    Memcached 的缺点: 

       1)  只能保存键值对数据,键值对只能是字符串,如果有对象数据只能自己序列化成 json 字符串;

       2)  数据保存在内存中,重启后会丢失;

       3)  Key 最大长度 255 个字符,Value 最长 1M。 

redis 命令行管理客户端:
1)直接启动 redis 安装目录下的 redis-cli 即可。不用管恶心的自动提示。 执行 set name yzk,就是设置键值对 name=yzk

执行 get name 就是查找名字是 name 的值;

keys *是查找所有的 key

key *n*是查找所有名字中含有 n 的 key

2) 和 Redis 一样,Redis 也是不同系统放到 Redis 中的数据都是不隔离的,因此设定 Key 的 时候也要选择好 Key。

3) Redis 服务器默认建了 16 个数据库,Redis 的想法是让大家把不同系统的数据放到不同 的数据库中。但是建议大家不要这样用,因为 Redis 是单线程的,不同业务都放到同一个 Redis 实例的话效率就不高,建议放到不同的实例中。因此尽量只用默认的 db0 数据库。

命令行下可以用 select 0、select 1 这样的指令切换数据库,最高为 15。试试在不同数据 库下新建、查询数据。

35、用过负载均衡吗

36、大数据处理

37、数据库表数据量特别大时,如何优化查询,提高速度?

38、数据库中如何循环读取数据库表中的记录?

      游标

39、数据库中删除重复数据

40、Session有什么缺点,微软如何改进

   这是道笔试题,我们知道IIS会回收资源,所以可能会导致Session失效

41、有没有用过消息队列

     RabbitMQ

42、设计一个老鼠、猫和主人的程序,要求可扩展性强,老鼠的叫声惊动猫和主人

    真无趣的一道题,用事件

43、Vue权限管理,如何控制界面的显示

44、WCF的部署方式

     一般在IIS上,还有人部署在Window服务上

45、简介应用程序池

46、冒泡算法

      c#写一个,双层循环

47、简述应用程序域

48、数据库设计三范式

49、SQL 事务的隔离级别有哪几个?

     sql 事务隔离级别有四种分种为:

     一 Read Uncommitted(未提交读)

     二 Read Committed(提交读)

     三 Repeated Read(可重复读)

      四 Serializable(序列)

      资料链接:https://www.cnblogs.com/wjwj/p/10719849.html

50、IQueryable和IEnumberable and IList与List区别      

 基本概念:
IEnumerable:使用的是LINQ to Object方式,它会将AsEnumerable()时对应的所有记录都先加载到内存,然后在此基础上再执行后来的Query
IQeurable(IQuerable<T>):不在内存加载持久数据,因为这家伙只是在组装SQL,(延迟执行) 到你要使用的时候,例如 list.Tolist() or list.Count()的时候,数据才从数据库进行加载 (AsQueryable())。
IList(IList<T>):泛型接口是 ICollection 泛型接口的子代,作为所有泛型列表的基接口,在用途方面如果作为数据集合的载体这是莫有问题的,只是如果需要对集合做各种的操作,例如 排序 编辑 统计等等,它不行。
List <> :泛型类,它已经实现了IList <> 定义的那些方法,IList<T> list=new List<T>();只是想创建一个基于接口IList<Class1>的对象的实例,这个接口是由List<T>实现的。只是希望使用到IList<T>接口规定的功能而已抽象场景:
其实在我们之前没有使用 ORM 的的很久很久以前,我们 在ADO.net 里面使用的 DataReader 和 DataAdapter or DataSet 和这几个货的基本原理都接近的,就是读取数据的时候,一个必须独占着数据库的连接,而另一个就是先把数据库的的局加载到了自己本地,然后再进行操作。
使用场景模拟:
//IList
IList users = res.ToList(); //此时已把users加载到内存,而每个user的关联实体 
                               //UserInfos)未被加载,所以下一行代码无法顺利通过
var ss = users.Where(p => p.UserInfos.ID != 3); //此处报错,因为P的UserInfos实体无法被加载  
// IQuerable的
IQueryable users = res.AsQueryable(); //users未被立即加载,关联实体可通过“延迟加载”获得
var ss = users.Where(p => p.UserInfos.ID != 3);//此处顺利获得对应的ss

  总结: 

基于性能和数据一致性这两点,使用IQueryable时必须谨慎,而在大多数情况下我们应使用IList。 

1.当你打算马上使用查询后的结果(比如循环作逻辑处理或者填充到一个table/grid中), 并且你不介意该查询即时被执行后的结果可以供调用者(Consummer)作后续查询(比如这是一个"GetAll"的方法),或者你希望该查执行,使用ToList()

2.当你希望查询后的结果可以供调用者(Consummer)作后续查询(比如这是一个"GetAll"的方法),或者你希望该查询延时执行,使用AsQueryable()

3.按照功能由低到高:List<T> IList<T> IQueryable<T> IEnumerable<T>

4.按照性能由低到高:IEnumerable<T> IQueryable<T> IList<T> List<T>

       参考链接:https://www.cnblogs.com/sunliyuan/p/5823419.html

 

原文地址:https://www.cnblogs.com/whitebai/p/11668972.html