C#面试题

这篇博客详细探讨了C#面试中常见的技术问题,涵盖了网络协议(TCP与UDP)、.NET框架、数据类型与内存管理、异常处理、数据结构、设计模式、数据库操作、Web开发、多线程和并发、安全、性能优化等多个方面。从抽象类与接口的差异到线程池的工作原理,再到数据库事务的ACID特性,深入浅出地解析了C#开发者在面试中可能遇到的各种问题。
摘要由CSDN通过智能技术生成

1.UDP和TCP连接有何异同?
传输控制协议(TCP):TCP协议是一种可靠的、一对一的、面向有连接的通信协议
用户数据报协议(UDP):UDP传输协议是一种不可靠的、面向无连接、可以实现多对一、一对多和一对一连接的通信协议

2.什么叫应用程序域?什么是托管代码?什么是强类型语言?
应用程序域:在.Net中,应用程序有了一个新的边界:应用程序域(以下简称域),它是一个用于隔离应用程序的虚拟边界,为了禁止不应交互的代码进行交互,这种隔离是必要的
托管代码:受CLR管理的代码
非托管代码:不受CLR管理的代码,比如数据库连接,文件读写…
强类型系统:强类型系统就是对每一个数据都有类型的限制,如C#,Java等属于强类型语言,javascript等属于弱类型语言

3.堆和栈的理解
引用类型创建的对象总是存放在堆中
值类型申明的变量和指针总是放在它们被声明的地方,存放在栈上

栈通常保存着我们代码执行的步骤,我们可以把栈想象成一个接着一个叠放在一
起的盒子(越高内存地址越低)。当我们使用的时候,每次从最顶部取走一个盒子,当一个方法(或类型)被调用完成的时候,就从栈顶取走,接着下一个
堆是无序的,他是一片不连续的内存域,像是一个仓库,储存着我们使用的各种对象等信息,跟栈不同的是他们被调用完毕不会立即被清理掉,通过垃圾回收器(GC)来回收

4.C#中序列化和反序列化
序列化是把一个内存中的对象的信息转化成一个可以持久化保存的形式,以便于保存或传输,序列化的主要作用是不同平台之间进行通信,常用的有序列化有json、xml、文件等。
序列化:将对象转化为容易传输的格式的过程
反:重新解析构造被序列化的对象
可以使用Newtosoft.json组件实现序列化

5.& 和 && 的区别
&运算符有两种用法:(1)按位与;(2)逻辑与
&&运算符是短路与运算。
逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true 整个表达式的值才是 true。如果&&左边的表达式的值是 false,右边的表达式会被直接短路掉,不会进行运算。

6.方法参数用ref修饰表示的是什么意思?
ref修饰的参数表示引用参数,引用参数不会创建新的副本,引用参数与实参指向同一内存地址。所以参数在方法内部修改后,调用者对应的实参本身也会发生变化

7.重载(overload)和重写(override)的区别?
方法的重载是发生在同一个类中的
判断重载:方法名一致,参数列表中参数的顺序,类型,个数不同。返回值可以不同

方法的重写是发生在父子类之间的
判断重写:方法名一致,参数列表必须完全与被重写方法的一致,返回类型必须完全与被重写方法的返回类型一致
构造方法和声明为final,static 的方法不能被重写
8.为什么函数不能根据返回类型来区分重载?(华为面试题)
因为调用时不能指定类型信息,编译器不知道你要调用哪个函数
float max(int a, int b);
int max(int a, int b);
当调用 max(1, 2);时无法确定调用的是哪个,单从这一点上来说,仅返回值类型不同的重载是不应该允许的。
void f() {}
int f() {}
若编译器可根据上下文(语境)明确判断出含义,比如在 int x=f()中,那么这样做完全没有问题。然而,我们也可能调用一个方法,同时忽略返回值;我们通常把这称为“为它的副作用去调用一个方法”,因为我们关心的不是返回值,而是方法调用的其他效果。所以假如我们像下面这样调用方法: f(); C#怎样判断 f()的具体调用方式呢?而且别人如何识别并理解代码呢?由于存在这一类的问题,所以不能。

9.char 型变量中能不能存储一个中文汉字,为什么?
但是在C#里面 char为两个字节 因为C# char型变量是用来存储Unicode编码的字符的,unicode编码字符集中包含了汉字,所以,char型变量中可以存储汉字。

10.抽象类(abstract class)和接口(interface)有什么异同?
不同:
抽象类: 1.抽象类中可以定义构造器 2.可以有抽象方法和具体方法 3.抽象类中的成员可以是 private、internal、protected、public 4.抽象类中可以定义成员变量 5.有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法 6.抽象类中可以包含静态方法 7.一个类只能继承一个抽象类
接口: 1.接口中不能定义构造器 2.方法全部都是抽象方法 3.接口中的成员全都是 public 的 4.接口中定义的成员变量实际上都是常量 5.接口中不能有静态方法 6.一个类可以实现多个接口

相同:
1.不能够实例化 2.可以将抽象类和接口类型作为引用类型 3.一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类

11.抽象的(abstract)方法是否=可同时是静态的(static)
不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。

12.阐述静态变量和实例变量的区别?
静态变量: 是被 static 修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;静态变量可以实现让多个对象共享内存;
实例变量: 必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。

13.break 和 continue 的区别?
break 和 continue 都是用来控制循环的语句。
break 用于完全结束一个循环,跳出循环体执行循环后面的语句。
continue 用于跳过本次循环,执行下次循环。

14.string s = “Hello”;s = s + " World!";这两行代码执行后,原始的string对象中的内容到底变了没有?
没有。因为 String 被设计成不可变(immutable)类,所以它的所有对象都是不可变对象。在这段代码中,s 原先指向一个 String 对象,内容是 “Hello”,然后我们对 s 进行了“+”操作,那么 s 所指向的那个对象是否发生了改变呢? 答案是没有。这时,s 不指向原来那个对象了,而指向了另一个 String 对象,内容为"Hello World!",原来那个对象还存在于内存之中,只是 s 这个引用变量不再指向它了。

通过上面的说明,我们很容易导出另一个结论,如果经常对字符串进行各种各样的修改,或者说不可预见的修改,那么使用 String进行加号拼接的方式会引起内存的内存开销。因为String对象建立之后不能再改变,所以对于每一个不同的字符串,都需要一个String对象来表示。因此我们平时推荐如果进行字符串的拼接操作的话使用StringBuilder类,它允许修改,而不是每个不同的字符串都要生成一个新的对象。并且,这两种类的对象转换十分容易。

15.请描述try catch finally的执行机制?
try代码块的代码出错之后会进入catch代码块执行,无论代码是否出错,都会进入finally代码块执行

16.数据类型之间的转换
其余类型的转换类似
int a = (int) b; //b只能是数字类型(例float,int,double,decimal等)
int a = int.Parse(b); //b只能是整型字符串类型
int a = Convert.ToInt32(b); //b的类型比较任意
int a = 0;
int.TryParse(b

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值