1.描述线程和进程的区别?前台线程和后台线程有什么区别?
线程和进程都定义了某种边界,进程的边界是应用程序之间的,线程则是代码执行堆栈和执行上下文的边界,一个进程可以有多个线程
前台线程可以通过Thread.IsBackground属性设置为true,将线程指定为后台线程。
前台可以通过结束所有线程来结束应用程序。后台则只能通过结束进程来结束程序。
2.Task状态机的实现和工作机制是什么?
await的作用和原理,并说明getResult()有什么区别?
task和Thread有区别吗?
3.线程池的优劣?Mutex和lock有什么不同?哪种好?
优点:减少线程创建和销毁的开销,可以复用线程,减少性能损失,提高GC回收率
(GC通常指的是“Garbage Collection”,即垃圾回收机制,用于自动管理内存,优化游戏性能。)
缺点:无法精确控制,没法设置优先级和返回值,对于长期运行的游戏不适合。
Mutex是基于内核模式的互斥锁,lock是混合锁,推荐用lock,性能更好。
4.浮点数精度问题?
解决方法:最好的是用字符串代替,牺牲大量内存换精度,
其次是通过成10的幂次来用int/long代替,
或者只计算一次,直接认定为准确值,防止多次计算结果不同。
5.IList接口与List的区别是什么?
IList接口是一个通用的接口,定义了一些与列表相关的操作,比如添加、删除、获取元素等。它是一个抽象的概念,并没有具体的实现。而List是一个具体的类,实现了IList接口,提供了列表的具体实现。
通过IList接口,可以访问和操作不同类型的列表,而不需要关心具体的实现类。而List作为一个具体的实现类,提供了更具体的功能和性能优化,操作效率更高。
可以通过IList接口来声明一个变量,然后使用具体的List类来实例化这个变量。这样可以在需要时灵活地替换实现类,而不需要修改其他代码。这也是面向接口编程的一个应用场景。
6.泛型的主要约束和次要约束是什么?
一个泛型参数至多有一个主要约束,主要约束可以是一个引用类型,class或者struct类型
次要约束主要是指实参中实现的接口的限定,对于一个泛型可以有0-n的次要约束。
7. .Net默认的委托类型有哪几种?结构体能实现接口吗?
Action<T> Fun<T>都有16种重载方法,
可以实现:
8.什么是委托?什么是泛型委托?什么是event,他和delegate什么关系
委托可以理解为持有一个或多个方法的对象,委托的本质和类一样,是一种用户自定义的类型。
委托可以增加程序的拓展性,多播委托就是把多个方法赋值给同一个委托。
Action就是泛型委托,
C#中的泛型委托是一种特殊类型的委托,它可以用于定义可以接受不同类型参数和返回不同类型结果的委托。与普通委托不同,泛型委托使用泛型参数来指定其参数和返回类型。
泛型委托可以通过在声明委托时使用泛型类型参数来定义。例如,可以定义一个可以接受任意类型参数并返回一个整数的泛型委托:
delegate T MyGenericDelegate<T>(T arg);
通过使用泛型委托,可以在运行时根据需要动态创建委托实例,并使用不同的参数类型和返回类型。这种灵活性使得泛型委托在处理不同类型参数和结果的情况下非常有用,例如在LINQ查询和事件处理中。
event在委托delegate上,又做了一次封装,限制用户直接操作delegate委托实例中变量的权限。
9.反射的实现原理?
反射是审查元数据,并收集关于它的类型信息的能力
优点:提高了程序的灵活性和拓展性,降低耦合性,提高自适应能力。缺点:性能问题,使用反射会模糊程序内部逻辑。
10.解释var和dynamic?如何避免类型转换时的异常?
将变量someValue声明为var而不是dynamic会引发错误,因为var不能更改变量的值并分配一个字符串值。
在只进行类型判断的场景,多用is而不是as
11.Dictionary底层原理
通过关键字key和value进行映射。对于Dictionary的实现原理,有两个关键算法,Hash算法和应对Hash碰撞的冲突解决算法。这是以数组为底层数据结构的类。Dictionary也是需要扩容的,会随着元素数量的增加而不断扩容。
12.C#的GC原理?& Unity的GC原理
(好好想想)
13.C#可否直接对内存操作?
unsafe模式下可以,一般模式或者托管模式都不可以(操作指针)
14.什么是匿名方法?什么是闭包?什么是装箱拆箱?如何避免效率问题?
匿名方法是用作委托的参数的一段代码。
通过lambda表达式可以访问lambda表达式块外部的变量,这成为闭包。
当引用外部变量时候,外部变量变化时,lambda表达式的结果也可能会随着外部变量变化而变化
把值类型实例转换为引用类型就是装箱,把引用类型转换为值类型,就是拆箱。
提升性能主要是尽量减少拆箱,装箱的操作,这很浪费CPU,
可以通过 struct通过重载函数来避免拆箱、装箱,
通过泛型来避免拆箱、装箱,
通过继承统一的接口提前拆箱、装箱,避免多次重复拆装。
15.C#中有哪些常用的容器类,有什么特点?构造函数是否能被重写?
Stack栈:先进后出 Queue队列:先进先出,表头表尾指针,通过size判空判满
Array:需要声明长度,不安全 ArrayList:动态增加数组,不安全
List:动态扩容,泛型安全。 Linklist:链表,插入删除效率高,访问查找效率低。 HashTable:查询速度快,添加速度慢。
构造器Constructor不能被继承,不能被重写,但可以被重载。
16.using的三种用法 C#的几种循环方式?
对命名空间的引用,定义命名空间的别名,自动释放所新建的对象。
有四种循环方式:for:确定次数的循环 foreach:使用于遍历的元素,只读
Do...while:次数不确定,条件随机变化,但至少要保证能被执行一次
while:次数不确定,条件随机变化。
17.接口是否可继承接口?抽象类是否可实现接口?抽象类是否可继承实现类?
用双检锁实现一个单例模式Singleton?
接口可以继承,抽象类可以实现,抽象类可以继承实现类,但前提实现类必须有明确的构造函数。
18.设计模式?你都知道哪些?什么是简单工厂模式?
设计模式共23种,总体分为三大类:创建型模式(工厂模式,单例模式)、结构型模式(适配器模式,外观模式)、行为型模式(观察者、访问者模式,迭代器模式,解释器模式)
静态工厂模式,通过建立一个工厂类,实现了同一接口的一些类进行实例的创建。例如咖啡机
优点:减少了使用者的记忆量,提高了系统的灵活性
缺点:不易拓展,一旦添加新的产品类型,就不得不修改工厂的创建逻辑
19.什么是强弱类型?哪种更好? set里的元素不能重复,怎么样区分重复与否呢?==还是equals() 什么是匿名类有什么好处? a.Equals(b) 和a == b 一样吗?
强类型是在编译的时候就确定类型的数据,执行时不能更改,弱类型在 执行时才会确定类型。
没有哪种更好,各有好坏,强类型效率高,弱类型比较灵活
iterator()区分,equals()是判读两个set是否相等。
不用定义没有名字的类是匿名类,使用一次便可丢弃,简单随意临时。
不一样,一个是数值相等 ,一个是完全一致
20.阐述什么是虚方法,与抽象方法有什么不同?是否可以从一个static方法内部发出对非static方法的调用?
一个虚方法必须有一个默认实现,而抽象方法没有实现,只在抽象类内部创建。
不可以,因为非static方法是要与对象关联在一起的,必须创建一个对象后才可以在该对象上进行方法调用,而static方法调用不需要创建对象,可以直接调用。
21.值类型和引用类型的区别?重载和重写的区别?ArrayList和List的主要区别?
值类型包含了所有简单类型等,引用类型string,struct,array,delegate值类型在内存栈中,引用类型在内存堆中。值类型存取快,引用类型慢,值类型是数据,引用类型是指针和引用。
重载是在同类中,重写在父子类中,方法名参数列表的区别,调用方式的区别,多态时机不同。
arraylist不带泛型,数据类型丢失,需要拆箱装箱 list带泛型,数据类型不丢失
22.list底层? linkedlist和list的区别?
list底层是数组,通过索引访问,索引越界时会抛出异常。增加操作时不够会自动扩容
list基于数组的数据结构可以随机访问,linkedlist基于链表的数据结构,插入删除方便
23.Interface和抽象类的区别? 构造函数是否能被重写?静态成员和非静态的区别?ref和out关键字有什么区别?
接口是完全抽象,抽象类是部分抽象,接口可以多继承,抽象类只能单继承,接口不能实例化,抽象类可以间接实例化。
构造器constructor不能被继承,因此不能重写,只能重载。
静态成员用static修饰符声明,类被第一次加载到内存时创建,通过类进行访问,静态成员属于类不属于对象,静态方法里不能使用非静态成员,非静态方法可以使用静态成员。
ref修饰引用参数,out修饰输出参数。
(后续再补)