基本语法:
参考文献:https://www.yuque.com/zhanglin-l1ak6/ll06t7/hpwe2e#8d95f1b4
string和StringBuilder的区别,两者性能的比较
都是引用类型,分配再堆上
StringBuilder默认容量是16,可以允许扩充它所封装的字符串中字符的数量.每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,
不会分配新的容量,当字符串大小超过容量时,会自动增加容量。
对于简单的字符串连接操作,在性能上stringbuilder不一定总是优于strin因为stringbulider对象的创建也消耗大量的性能,
在字符串连接比较少的情况下,过度滥用stringbuilder会导致性能的浪费而非节约,只有大量无法预知次数的字符串操作才考虑stringbuilder的使用。
从最后分析可以看出如果是相对较少的字符串拼接根本看不出太大差别。
什么是扩展方法? 一句话解释,扩展方法使你能够向现有类型“添加”方法,无需修改类型 条件:按扩展方法必须满足的条件,1.必须要静态类中的静态方法 2.第一个参数的类型是要扩展的类型,并且需要添加this关键字以标识其为扩展方法
什么是装箱和拆箱?
装箱就是隐式地将一个值类型转换成引用类型
拆箱就是将引用类型转换成值类型
值类型和引用类型的区别 值类型变量是直接包含值。将一个值类型变量赋给另一个值类型变量,是复制包含的值,默认值是0。 引用类型变量的赋值只复制对对象的引用,而不复制对象本身,默认值是null 值类型有整形、浮点型、bool、枚举。 引用类型有class、delegate、Object、string 值类型存储在栈中,引用类型存储在堆中
C#中的委托是什么?
将方法当作参数传入另一个方法的参数。
.net中有很多常见的委托如:Func 、Action 作用:提高方法的扩展性
Func和Action委托的唯一区别在于Func要有返回值, Action没有返回值。
用最有效的方法算出2乘以8等于几? 位运算是最快,使用的是位运算 逻辑左位移<<。 方法是2<<3相当于0000 0000 0000 0010 (2的16位int二进制) 左移三位就是 0000 0000 0001 0000(16的二进制)
const和readonly有什么区别? 都可以标识一个常量。主要有以下区别: 1、初始化位置不同。const必须在声明的同时赋值;readonly即可以在声明处赋值也可以在静态构造方法 必须是静态构造方法,普通构造方法不行)里赋值。 2、修饰对象不同。const即可以修饰类的字段,也可以修饰局部变量;readonly只能修饰类的字段 3、const是编译时常量,在编译时确定该值;readonly是运行时常量,在运行时确定该值。 4、const默认是静态的;而readonly如果设置成静态需要显示声明 5、修饰引用类型时不同,const只能修饰string或值为null的其他引用类型;readonly可以是任何类型。
静态成员和非静态成员的区别 1.静态成员用statis修饰符声明,在类被实例化时创建,通过类进行访问 2.不带statis的变量时非静态变量,在对象被实例化时创建,通过对象进行访问, 3.静态方法里不能使用非静态成员,非静态方法可以使用静态成员 4.静态成员属于类,而不属于对象
c#可否对内存直接操
C#在unsafe 模式下可以使用指针对内存进行操作, 但在托管模式下不可以使用指针,C#NET默认不运行带指针的
什么是强类型,什么是弱类型?哪种更好些?为什么?
强类型是在编译的时候就确定类型的数据,在执行时类型不能更改,而弱类型在执行的时候才会确定类型。
没有好不好,二者各有好处,强类型安全,因为它事先已经确定好了,而且效率高。
面向对象
什么是构造函数
构造函数的方法名与类型相同、没有返回类型
class和struct的区别?
相同点 都可以实现接口
不同点
class是引用类型,struct是值类型
class允许继承、被继承,struct不允许,只能继承接口
抽象类和接口有什么区别? 相同点:都不能直接实例化 不同点
1.抽象类用abstract修饰、接口用interface修饰 2.抽象类中的方法可以实现,也可以不实现,有抽象方法的类一定要用abstract修饰,接口中的方法不允许实现 3.抽象类只能单继承,接口支持多实现 4.抽象类有构造方法,接口不能有构造方法 5.接口只负责功能的定义,通过接口来规范类的, (有哪些功能),而抽象类即负责功能的定义有可以实现功能 (实现了哪些功能)
类的执行顺序?
执行顺序:父类,子类,静态块,静态字段,非静态块,
非静态字段,构造器,方法
接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实现类(concrete class)? 接口可以继承接口,抽象类可以实现接口, 抽象类可以继承实现类, 但前提是实现类必须有明确的构造函数。
继承最大的好处?
对父类成员进行重用,增加代码的可读性、灵活性。
什么是匿名类,有什么好处?
不用定义、没有名字的类,使用一次便可丢弃。好处是简单、随意、临时的。
重写和重载的区别?
重写方法:关键字用override修饰,派生类重写基类的方法,方法命名、返回类型,参数必须相同
重载方法:方法名必须相同,参数列表必须不相同,返回类型可以不相同。
作用:重写主要是实现面向对象的多态性、重载主要是实现实例化不同的对象
集合、异常、泛型、LINQ、委托、EF
IList 接口与List的区别是什么?
IList 泛型接口是 Icollection 接口的子代,并且是所有非泛型列表的基接口。 Ilist 实现有三种类别:只读、固定大小、可变大小。 无法修改只读 Ilist。
固定大小的 Ilist 不允许添加或移除元素,但允许修改现有元素。
可变大小的 Ilist 允许添加、移除和修改元素。
List 是个类型 已经实现了IList 定义的那些方法。
泛型的主要约束和次要约束是什么?
当一个泛型参数没有任何约束时,它可以进行的操作和运算是非常有限的,
因为不能对实参进行任何类型上的保证,这时候就需要用到泛型约束。
泛型的约束分为:主要约束和次要约束,它们都使实参必须满足一定的规范,C#编译器在编译的过程中可以根据约束来检查所有泛型类型的实参并确保其满足约束条件。
什么是泛型委托? Action就是泛型委托。 .建议尽量使用这些委托类型,而不是在代码中定义更多的委托类型。这样可以减少系统中的类型数目,同时简化编码 如果需要使用ref或out关键字,以传引用的方式传递一个参数,就可能不得不定义自己的委托:delegate void Test(ref int i)
什么是匿名方法? 匿名方法是用作委托的参数的一段代码。 //匿名方法,例1 Func<int, int> anon = delegate(int i) { i = i+1; return i; }; //输出2 Console.WriteLine(anon(1)); //匿名方法,例2 Action<int> anon2 = delegate(int i) { i = i + 1; }; //输出2 Console.WriteLine(anon(1));
如何提高LINQ性能问题?
提升从数据库中拿数据的速度,可以参考以下几种方法:
在数据库中的表中定义合适的索引和键
只获得你需要的列(使用ViewModel或者改进你的查询)和行(使用IQueryable)
尽可能使用一条查询而不是多条
只为了展示数据,而不进行后续修改时,可以使用AsNoTracking。它不会影响生成的SQL,但它可以令系统少维护很多数据,从而提高性能
什么是协变和逆变? 协变和逆变一般应用于泛型接口和泛型委托中; 协变和逆变主要是为了保证某些类型在特殊数据结构中变型时的类型安全; 简单类型父类的变量能指向子类B的对象,此时,若IEnumerable<A>类型的变量能指向IEnumerable<B>的对象,为协变;若若IEnumerable<B>类型的变量能指向IEnumerable<A>的对象,为逆变; 协变”->”和谐的变”->”很自然的变化”->string->object :协变,类型参数只能作为输类型;“逆变”->”逆常的变”->”不正常的变化”->object->string 逆变,类型参数只能作为输入参数类型。
延迟执行 (Lazy Loading)是什么?
大部分LINQ语句是在最终结果的第一个元素被访问的时候(即在foreach中调用MoveNext方法)才真正开始运算的,这个特点称为延迟执行。一般来说,返回另外一个序列(通常为IEnumerable或IQueryable)的操作,使用延迟执行,而返回单一值的运算,使用立即执行。
try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后? 会执行,在return前执行。
泛型有哪些常见的约束?
泛型约束 public void GetEntity() 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必须是引用类型,并且要有一个无参的构造函数(对于一个类型有多有约束,中间用逗号隔开)
能用foreach 遍历访问的对象的要求?
需要实现IEnumerable接口或声明GetEnumerator方法的类型。
说出五个集合类? List:泛型类; Stack:堆栈,后进先出的访问各个元素 Dictionary<TKey, TValue>:字典类,key是区分大小写;value用于存储对应于key的值 HashSet:此集合类中不能有重复的子元素 SortedList<TKey, TValue>:排序列表,key是排好序的数组。
多线程
Windows单个进程所能访问的最大内存量是多少?它与系统的最大虚拟内存一样吗?这对于系统设计有什么影响? 这个需要针对硬件平台,公式为单个进程能访问的最大内存量=2的处理器位数次方/2,
比如通常情况下,32位处理器下,单个进程所能访问的最大内存量为:232 /2 = 2G 。
单个进程能访问的最大内存量是最大虚拟内存的1/2,因为要分配给操作系统一半虚拟内存。
using() 语法有用吗?什么是IDisposable? 有用,实现了IDisposiable的类在using中创建, using结束后会自定调用该对象的Dispose方法,释放资源
前台线程和后台线程有什么区别? 通过将 Thread.IsBackground 属性设置为 true, 就可以将线程指定为后台线程 前台线程: 应用必须结束掉所有的前台线程才能结束程序, 只要有一个前台线程没退出进程就不会自动退出, 当然线程是依附在进程上的, 所以你直接把进程KO掉了的话自然所有前台线程也会退出。 后台线程: 进程可以不考虑后台直接自动退出, 进程自动退出后所有的后台线程也会自动销毁。
Task状态机的实现和工作机制是什么? CPS全称是Continuation Passing Style, 在.NET中,它会自动编译为: 1. 将所有引用的局部变量做成闭包,放到一个隐藏的状态机的类中; 2. 将所有的await展开成一个状态号,有几个await就有几个状态号; 3. 每次执行完一个状态,都重复回调状态机的MoveNext方法,同时指定下一个状态号; 4. MoveNext方法还需处理线程和异常等问题
Task和Thread有区别吗? Task和Thread都能创建用多线程的方式执行代码,但它们有较大的区别。 Task较新,发布于.NET 4.5,能结合新的async/await代码模型写代码 ,它不止能创建新线程,还能使用线程池(默认)、单线程等方式编程, 在UI编程领域,Task还能自动返回UI线程上下文, 还提供了许多便利API以管理多个Task。
await的作用和原理,并说明和GetResult()有什么区别?
从状态机的角度出发,await的本质是调用Task.GetAwaiter()的UnsafeOnCompleted(Action)回调,并指定下一个状态号。
从多线程的角度出发,如果await的Task需要在新的线程上执行,
该状态机的MoveNext()方法会立即返回,
此时,主线程被释放出来了,然后在UnsafeOnCompleted回调的
action指定的线程上下文中继续MoveNext()和下一个状态的代码。
而相比之下,GetResult()就是在当前线程上立即等待Task的完成,
在Task完成前,当前线程不会释放。
注意:Task也可能不一定在新的线程上执行,
此时用GetResult()或者await就只有会不会创建状态机的区别了。
两个线程交替打印0~100的奇偶数 这道题就是说有两个线程,一个名为偶数线程,一个名为奇数线程, 偶数线程只打印偶数,奇数线程只打印奇数,两个线程按顺序交替打印。 publicclassThreadExample { ///<summary> ///两个线程交替打印0~100的奇偶数 ///</summary> public static void PrintOddEvenNumber { varwork = newTheadWorkTest; varthread1 = newThread(work.PrintOddNumer) { Name = "奇数线程"}; varthread2 = newThread(work.PrintEvenNumber) { Name = "偶数线程"}; thread1.Start; thread2.Start; } } publicclassTheadWorkTest { privatestaticreadonlyAutoResetEvent oddAre = newAutoResetEvent( false); privatestaticreadonlyAutoResetEvent evenAre = newAutoResetEvent( false); publicvoidPrintOddNumer { oddAre.WaitOne; for( var0; i < 100; i++ ) { if(i % 2!= 1) continue; Console.WriteLine($"{Thread.CurrentThread.Name}:{i}"); evenAre.Set; oddAre.WaitOne; } } publicvoidPrintEvenNumber { for( vari = 0; i < 100; i++ ) { if(i % 2!= 0) continue; Console.WriteLine($"{Thread.CurrentThread.Name}:{i}"); oddAre.Set; evenAre.WaitOne; } } }
说说常用的锁,lock是一种什么样的锁?
常用的如如SemaphoreSlim、ManualResetEventSlim、Monitor、ReadWriteLockSlim,lock是一个混合锁,其实质是Monitor
lock为什么要锁定一个参数(可否为值类型?)参数有什么要求?
lock的锁对象要求为一个引用类型。她可以锁定值类型,但值类型会被装箱,
每次装箱后的对象都不一样,会导致锁定无效。
对于lock锁,锁定的这个对象参数才是关键,
这个参数的同步索引块指针会指向一个真正的锁(同步块),
这个锁(同步块)会被复用。
多线程和异步的区别和联系?
多线程是实现异步的主要方式之一,异步并不等同于多线程。
实现异步的方式还有很多,比如利用硬件的特性、使用进程或协程等。
在.NET中就有很多的异步编程支持,比如很多地方都有Begin、End 的方法,就是一种异步编程支持,她内部有些是利用多线程,有些是利用硬件的特性来实现的异步编程。
Mutex和lock有什么不同?一般用哪一种比较好?
Mutex是一个基于内核模式的互斥锁,支持锁的递归调用,而Lock是一个混合锁,一般建议使用Lock更好,因为lock的性能更好。
用双检锁实现一个单例模式Singleton。 public static class Singleton<T> where T : class,new() { private static T _Instance; private static object _lockObj = new object(); /// <summary> /// 获取单例对象的实例 /// </summary> public static T GetInstance() { if (_Instance != null) return _Instance; lock (_lockObj) { if (_Instance == null) { var temp = Activator.CreateInstance<T>(); System.Threading.Interlocked.Exchange(ref _Instance, temp); } } return _Instance; } }
Thread 类有哪些常用的属性和方法? CurrentContext:获取线程正在其中执行的当前上下文。 CurrentCulture:获取或设置当前线程的区域性。 CurrentPrincipal:获取或设置线程的当前负责人(对基于角色的安全性而言)。 CurrentThread:获取当前正在运行的线程。 CurrentUICulture:获取或设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源。 IsBackground:获取或设置一个值,该值指示某个线程是否为后台线程。 Priority:获取或设置一个值,该值指示线程的调度优先级。 ThreadState:获取一个值,该值包含当前线程的状态。 方法: public void Abort() 在调用此方法的线程上引发 ThreadAbortException,以开始终止此线程的过程。调用此方法通常会终止线程。 public void Start() 开始一个线程。 public static void Sleep( int millisecondsTimeout ) 让线程暂停一段时间。 public static bool Yield() 调用线程执行准备好在当前处理器上运行的另一个线程。