.NET/C#⾯试题汇总系列:集合、异常、泛型、 LINQ、委托、EF【系统整合篇】

1. IList 接⼝与List的区别是什么?

IList 泛型接⼝是 Icollection 接⼝的⼦代,并且是所有⾮泛型列表的基接⼝。 Ilist 实现有三种类别:只读、固定⼤⼩、可变⼤⼩。 ⽆法修改只读 Ilist。 固定⼤⼩的 Ilist 不允许添加或移除元素,但允许修改现有元素。 可变⼤⼩的 Ilist 允许添加、移除和修改元素。
IList 是个接⼝,定义了⼀些操作⽅法这些⽅法要你⾃⼰去实现,当你只想使⽤接⼝的⽅法时,这种⽅式⽐较好.他不获取实现这个接⼝的类的其他⽅法和字段,有效的节省空间.
List 是个类型 已经实现了IList 定义的那些⽅法。

List List11 =new List ();

是想创建⼀个List,⽽且需要使⽤到List的功能,进⾏相关操作。

IList IList11 =new List ();

⽽只是想创建⼀个基于接⼝IList的对象的实例,只是这个接⼝是由List实现的。所以它只是希望使⽤到IList接⼝规定的功能⽽已。

2.泛型的主要约束和次要约束是什么?

当⼀个泛型参数没有任何约束时,它可以进⾏的操作和运算是⾮常有限的,因为不能对实参进⾏任何类型上的保证,这时候就需要⽤到泛型约束。泛型的约束分为:主要约束和次要约束,它们都使实参必须满⾜⼀定的规范,C#编译器在编译的过程中可以根据约束来检查所有泛型类型的实参并确保其满⾜约束条件。
(1)主要约束
⼀个泛型参数⾄多拥有⼀个主要约束,主要约束可以是⼀个引⽤类型、class或者struct。如果指定⼀个引⽤类型(class),那么实参必须是该类型或者该类型的派⽣类型。相反,struct则规定了实参必须是⼀个值类型。下⾯的代码展示了泛型参数主要约束:

 public class ClassT1<T> where T : Exception
 {
    
    
 	private T myException;
	public ClassT1(T t)
	 {
    
    
		 myException = t;
	 }
	 public override string ToString()
	 {
    
    
		// 主要约束保证了myException拥有source成员
		return myException.Source;
 	}
}
public class ClassT2<T> where T : class
 {
    
    
	 private T myT;
 	public void Clear()
 	{
    
    
		 // T是引⽤类型,可以置null
		 myT = null;
	 }
}

 public class ClassT3<T> where T : struct
 {
    
    
	private T myT;
 	public override string ToString()
	 {
    
    
 		// T是值类型,不会发⽣NullReferenceException异常
 		return myT.ToString();
	}

(2)次要约束
次要约束主要是指实参实现的接⼝的限定。对于⼀个泛型,可以有0到⽆限的次要约束,次要约束规定了实参必须实现所有的次要约束中规定的接⼝。次要约束与主要约束的语法基本⼀致,区别仅在于提供的不是⼀个引⽤类型⽽是⼀个或多个接⼝。例如我们为上⾯代码中的ClassT3增加⼀个次要约束:

 public class ClassT3<T> where T : struct, IComparable
 {
    
    
 ......
 }

3. 如何把⼀个array复制到arrayist⾥?

foreach( object arr in array)
{
    
    
	 arrayist.Add(arr);//还有其他的几种方式,比如AddRange
}

4.List, Set, Map是否继承⾃Collection接⼝?

List,Set是,Map不是

5. Set⾥的元素是不能重复的,那么⽤什么⽅法来区分重复与否呢? 是⽤==还是equals()? 它们有何区别?

Set⾥的元素是不能重复的,那么⽤iterator()⽅法来区分重复与否。equals()是判读两个Set是否相等。
equals()和==⽅法决定引⽤值是否指向同⼀对像,equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。

6.有50万个int类型的数字,现在需要判断⼀下⾥⾯是否存在重复的数字,请你简要说⼀下思路。

1.使⽤C#的List集合⾃带的去重⽅法,例如 Distinct(),GroupBy()等
2.利⽤ Dictionary 的Key值唯⼀的特性,HashSet 元素值唯⼀的特性 进⾏判断

7.数组有没有length()这个⽅法? String有没有length()这个⽅法?

数组没有length()这个⽅法,有length的属性。String有有length()这个⽅法。

8.⼀个整数List中取出最⼤数(找最⼤值)。不能⽤Max⽅法。

private static int GetMax(List<int> list)
 {
    
    
	 int max = list[0];
	 for (int i = 0; i < list.Count; i++)
 	{
    
    
		 if (list[i]>max)
		 {
    
    
			max = list[i];
		 }
	 }
	 return max;
 }

9. C#异常类有哪些信息?

C#中,所有异常都继承⾃System.Exception类,Exception类定义了C#异常应该具有的信息和⽅法。值得注意的属性有:
1 public virtual string Message { get; }// 错误的信息,⽂字描述
2 public virtual string StackTrace { get; }// 发⽣异常的调⽤堆栈信息
3 public System.Reflection.MethodBase TargetSite { get; }//引发这个错误的⽅法
4 public Exception InnerException { get; }// ⼦异常

10. 如何创建⼀个⾃定义异常?

根据类继承原则和异常处理原则,我们可以使⽤以下⽅式来⾃定义⼀个类:

扫描二维码关注公众号,回复: 16468416 查看本文章
 public class CustomException : Exception
{
    
    
}

11. 利⽤IEnumerable实现斐波那契数列⽣成?

IEnumerable<int> GenerateFibonacci(int n)
 {
    
    
 	if (n >= 1) yield return 1;
 	int a = 1, b = 0;
	for (int i = 2; i <= n; ++i)
 	{
    
    
		 int t = b;
		 b = a;
		 a += t;
		 yield return a;
 	}
 }

12.请利⽤ foreach 和 ref 为⼀个数组中的每个元素加 1

注意 foreach 不能⽤ var ,也不能直接⽤ int ,需要 ref int ,注意 arr 要转换为 Span

 int[] arr = {
    
     1, 2, 3, 4, 5};
 Console.WriteLine(string.Join(",", arr)); // 1,2,3,4,5
foreach (ref int v in arr.AsSpan())
 {
    
    
 	v++;
}
Console.WriteLine(string.Join(",", arr)); // 2,3,4,5,6

13.如何针对不同的异常进⾏捕捉?

 public class Program
    {
    
    
        public static void Main(string[] args)
        {
    
    
            Program p = new Program();
            p.RiskWork();

            Console.ReadKey();
        }

        public void RiskWork()
        {
    
    
            try
            {
    
    
                // ⼀些可能会出现异常的代码
            }
            catch (NullReferenceException ex)
            {
    
    
                HandleExpectedException(ex);
            }
            catch (ArgumentException ex)
            {
    
    
                HandleExpectedException(ex);
            }
            catch (FileNotFoundException ex)
            {
    
    
                HandlerError(ex);
            }
            catch (Exception ex)
            {
    
    
                HandleCrash(ex);
            }
        }
        // 这⾥处理预计可能会发⽣的,不属于错误范畴的异常
        private void HandleExpectedException(Exception ex)
        {
    
    
            // 这⾥可以借助log4net写⼊⽇志
            Console.WriteLine(ex.Message);
        }

        // 这⾥处理在系统出错时可能会发⽣的,⽐较严重的异常
        private void HandlerError(Exception ex)
        {
    
    
            // 这⾥可以借助log4net写⼊⽇志
            Console.WriteLine(ex.Message);
            // 严重的异常需要抛到上层处理
            throw ex;
        }
        // 这⾥处理可能会导致系统崩溃时的异常
        private void HandleCrash(Exception ex)
        {
    
    
            // 这⾥可以借助log4net写⼊⽇志
            Console.WriteLine(ex.Message);
            // 关闭当前程序
            System.Threading.Thread.CurrentThread.Abort();
        }
    }

14.如何避免类型转换时的异常?

其中有些是确定可以转换的(⽐如将⼀个⼦类类型转为⽗类类型),⽽有些则是尝试性的(⽐如将基类引⽤的对象转换成⼦类)。当执⾏常识性转换时,我们就应该做好捕捉异常的准备。
当⼀个不正确的类型转换发⽣时,会产⽣InvalidCastException异常,有时我们会⽤try-catch块做⼀些尝试性的类型转换,这样的代码没有任何错误,但是性能却相当糟糕,为什么呢?异常是⼀种耗费资源的机制,每当异常被抛出时,异常堆栈将会被建⽴,异常信息将被加载,⽽通常这些⼯作的成本相对较⾼,并且在尝试性类型转换时,这些信息都没有意义。
在.NET中提供了另外⼀种语法来进⾏尝试性的类型转换,那就是关键字 is 和 as 所做的⼯作。
(1)is 只负责检查类型的兼容性,并返回结果:true 和 false。→ 进⾏类型判断

    public static void Main(string[] args)
        {
    
    
            object o = new object();
            // 执⾏类型兼容性检查
            if (o is ISample)
            {
    
    
                // 执⾏类型转换
                ISample sample = (ISample)o;
                sample.SampleShow();
            }

            Console.ReadKey();
        }

(2)as 不仅负责检查兼容性还会进⾏类型转换,并返回结果,如果不兼容则返回 null 。→ ⽤于类型转型

 public static void Main(string[] args)
        {
    
    
            object o = new object();
            // 执⾏类型兼容性检查
            ISample sample = o as ISample;
            if (sample != null)
            {
    
    
                sample.SampleShow();
            }
            Console.ReadKey();
        }

两者的共同之处都在于:不会抛出异常!综上⽐较,as 较 is 在执⾏效率上会好⼀些,在实际开发中应该量才⽽⽤,在只进⾏类型判断的应⽤场景时,应该多使⽤ is ⽽不是 as。

15.Serializable特性有什么作⽤?

通过上⾯的流类型可以⽅便地操作各种字节流,但是如何把现有的实例对象转换为⽅便传输的字节流,就需要使⽤序列化技术。对象实例的序列化,是指将实例对象转换为可⽅便存储、传输和交互的流。在.NET中,通过Serializable特性提供了序列化对象实例的机制,当⼀个类型被申明为Serializable后,它就能被诸如BinaryFormatter等实现了IFormatter接⼝的类型进⾏序列化和反序列化

16.委托是什么?

委托是寻址的.NET版本。在C++中,函数指针只不过是⼀个指向内存位置的指针,它不是类型安全的。我们⽆法判断这个指针实际指向什么,像参数和返回类型等项久更⽆从知晓了。
⽽.NET委托完全不同,委托是类型安全的类,它定义了返回类型和参数的类型。委托类不仅包含对⽅法的引⽤,也可以包含对多个⽅法的引⽤。

17.如何⾃定义委托?

声明⼀个委托类型,它的实例引⽤⼀个⽅法,该⽅法获取⼀个int参数,返回void。

public delegate void Feedback(int num);

理解委托的⼀个要点是它们的安全性⾮常⾼。在定义委托时,必须给出它所表示的⽅法的签名和返回类型等全部细节。
理解委托的⼀种⽐较好的⽅式是把委托当作这样⼀件事情:它给⽅法的签名和返回类型指定名称。其语法类似于⽅法的定义,需要在定义⽅法的前⾯加上delegate关键字。定义委托基本上就是定义⼀个新的类,所以可以在任何地⽅定义类的相同地⽅定义委托,也就是说,可以在另⼀个类的内部定义,也可以在任何类的外部定义,还可以在名称控件中把委托定义为定义为顶层对象。访问修饰符可以是public/private/protected等。

18 .NET默认的委托类型有哪⼏种?

  1. Action < T >
    泛型Action委托表示引⽤⼀个void返回类型的⽅法。这个委托类存在16种重载⽅法。例如Action<in T1,In T2>调⽤没有参数的⽅法

2.Func< T >
Func调⽤带返回类型的⽅法。有16种重载⽅法。
例如Func委托类型可以调⽤带返回类型且⽆参数的⽅法,Func<in T,out TResult>委托类型调⽤带有4个参数和⼀个返回类型的⽅法。

19.什么是泛型委托?

Action就是泛型委托。
注意事项:
1.建议尽量使⽤这些委托类型,⽽不是在代码中定义更多的委托类型。这样可以减少系统中的类型数⽬,同时简化编码
2.如果需要使⽤ref或out关键字,以传引⽤的⽅式传递⼀个参数,就可能不得不定义⾃⼰的委托:

delegate void Test(ref int i)

3.如果委托要通过C#的params关键字获取可变数量的额参数,要为委托的任何桉树指定默认值,或者要对委托的泛型类型参数进⾏约束,也必须定义⾃⼰的委托类型

delegate void EventHandler(Object sender, TEventArgs e)
where TEventArgs : EventArgs;

4.使⽤获取泛型实参和返回值的委托时,可利⽤逆变与协变。逆变:⽗类转换为⼦类;协变:⼦类转换为⽗类

20. 什么事匿名⽅法?

匿名⽅法是⽤作委托的参数的⼀段代码。

 //匿名⽅法,例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));

21.什么是闭包?

通过Lambda表达式可以访问Lambda表达式块外部的变量,这成为闭包。
当引⽤外部变量时,需要注意,外部变量变化时,lambda表达式的结果也可能会随着外部变量变化⽽变化。
如下⾯的例⼦:

int y = 5;
Func<int, int> lambda = x => x + y;
Console.WriteLine(lambda(1));
y = 10;
Console.WriteLine(lambda(1));

22.EF(Entity Framework)是什么?

实体框架EF是http://ADO.NET中的⼀组⽀持开发⾯向数据的软件应⽤程序的技术,是微软的⼀个ORM框架。
主要有三种⽅式:
Database FirstDatabase First”模式
我们称之为“数据库优先”,前提是你的应⽤已经有相应的数据库,你可以使⽤EF设计⼯具根据数据库⽣成数据数据类,你可以使⽤Visual Studio模型设计器修改这些模型之间对应关系。
Model FirstModel First我们称之为“模型优先”,这⾥的模型指的是“ADO.NET Entity Framework Data Model”,此时你的应⽤并没有设计相关数据库,在Visual Studio中我们通过设计对于的数据模型来⽣成数据库和数据类。
Code FirstCode First模式我们称之为“代码优先”模式,是从EF4.1开始新建加⼊的功能。
使⽤Code First模式进⾏EF开发时开发⼈员只需要编写对应的数据类(其实就是领域模型的实现过程),然后⾃动⽣成数据库。这样设计的好处在于我们可以针对概念模型进⾏所有数据操作⽽不必关⼼数据的存储关系,使我们可以更加⾃然的采⽤⾯向对象的⽅式进⾏⾯向数据的应⽤程序开发。

23.什么是ORM?

ORM指的是⾯向对象的对象模型和关系型数据库的数据结构之间的互相转换。
(表实体跟表之间的相互转换)
ORM框架有很多,EF框架是ORM框架的其中⼀种,是实现了ORM思想的框架。
O=>表实体
M=>映射关系
R=>数据库.表

24.为什么⽤EF⽽不⽤原⽣的ADO.NET?

1.极⼤的提⾼开发效率:EF是微软⾃⼰的产品,开发中代码都是强类型的,
xiefl代码效率⾮常⾼,⾃动化程度⾮常⾼,命令式的编程.
2.EF提供的模型设计器⾮常强⼤,不仅仅带来了设计数据库的⾰命,也附带来的⾃动化模型代码的功能也极⼤的提⾼开发和架构设计的效率.
3.EF跨数据⽀持的是ORM框架主要功能点之⼀,带来的是可以通过仅仅改变配置就可以做到跨数据库的能⼒

25.如何提⾼LINQ性能问题?

提升从数据库中拿数据的速度,可以参考以下⼏种⽅法:
1.在数据库中的表中定义合适的索引和键
2.只获得你需要的列(使⽤ViewModel或者改进你的查询)和⾏(使⽤IQueryable)
3.尽可能使⽤⼀条查询⽽不是多条
4.只为了展示数据,⽽不进⾏后续修改时,可以使⽤AsNoTracking。它不会影响⽣成的SQL,但它可以令系统少维护很多数据,从⽽提⾼性能
5.使⽤Reshaper等⼯具,它可能会在你写出较差的代码时给出提醒

26.什么是协变和逆变?

可变性是以⼀种类型安全的⽅式,将⼀个对象作为另⼀个对象来使⽤。其对应的术语则是不变性(invariant)。
可变性:
可变性是以⼀种类型安全的⽅式,将⼀个对象作为另⼀个对象来使⽤。例如对普通继承中的可变性:若某⽅法声明返回类型为Stream,在实现时可以返回⼀个MemoryStream。可变性有两种类型:协变和逆变。
协变性:
可以建⽴⼀个较为⼀般类型的变量,然后为其赋值,值是⼀个较为特殊类型的变量。例如:

 string str = "test";
  // An object of a more derived type is assigned to an object of a
less derived type.
 object obj = str;

因为string肯定是⼀个object,所以这样的变化⾮常正常。
逆变性:在上⾯的例⼦中,我们⽆法将str和⼀个新的object对象画等号。如果强⾏要实现的话,只能这么⼲:

 string s = (string) new object();

但这样还是会在运⾏时出错。这也告诉我们,逆变性是很不正常的。
泛型的协变与逆变:
协变性和out关键字搭配使⽤,⽤于向调⽤者返回某项操作的值。例如下⾯的接⼝仅有⼀个⽅法,就是⽣产⼀个T类型的实例。那么我们可以传⼊⼀个特定类型。如我们可以将IFactory视为IFactory。这也适⽤于Food的所有⼦类型。(即将其视为⼀个更⼀般类型的实现)

interface IFactory<T>
 {
    
    
	 T CreateInstance();
}

逆变性则相反,和in关键字搭配使⽤,指的是API将会消费值,⽽不是⽣产值。此时⼀般类型出现在参数中:

interface IPrint<T>
 {
    
    
	 void Print(T value);
 }

这意味着如果我们实现了IPrint< Code >,我们就可以将其当做IPrint< CsharpCode >使⽤。(即将其视为⼀个更具体类型的实现)
如果存在双向的传递,则什么也不会发⽣。这种类型是不变体(invariant)。

interface IStorage<T>
 {
    
    
 byte[] Serialize(T value);
 T Deserialize(byte[] data);
 }

这个接⼝是不变体。我们不能将它视为⼀个更具体或更⼀般类型的实现。
假设有如下继承关系People –> Teacher,People –> Student。
如果我们以协变的⽅式使⽤(假设你建⽴了⼀个IStorage< Teacher >的实例,并将其视为IStorage)则我们可能会在调⽤Serialize时产⽣异常,因为Serialize⽅法不⽀持协变(如果参数是People的其他⼦类,例如Student,则IStorage< Teacher >将⽆法序列化Student)。
如果我们以逆变的⽅式使⽤(假设你建⽴了⼀个IStorage的实例,并将其视为IStorage< Teacher >),则我们可能会在调⽤Deserialize时产⽣异常,因为Deserialize⽅法不⽀持逆变,它只能返回People不能返回Teacher。

27.什么是IEnumerable?

IEnumerable及IEnumerable的泛型版本IEnumerable是⼀个接⼝,它只含有⼀个⽅法GetEnumerator。Enumerable这个静态类型含有很多扩展⽅法,其扩展的⽬标是IEnumerable。
实现了这个接⼝的类可以使⽤Foreach关键字进⾏迭代(迭代的意思是对于⼀个集合,可以逐⼀取出元素并遍历之)。实现这个接⼝必须实现⽅法GetEnumerator。

28.IEnumerable的缺点有哪些?

IEnumerable功能有限,不能插⼊和删除。
访问IEnumerable只能通过迭代,不能使⽤索引器。迭代显然是⾮线程安全的,每次IEnumerable都会⽣成新的IEnumerator,从⽽形成多个互相不影响的迭代过程。
在迭代时,只能前进不能后退。新的迭代不会记得之前迭代后值的任何变化。

29.延迟执⾏ (Lazy Loading)是什么?

⼤部分LINQ语句是在最终结果的第⼀个元素被访问的时候(即在foreach中调⽤MoveNext⽅法)才真正开始运算的,这个特点称为延迟执⾏。⼀般来说,返回另外⼀个序列(通常为IEnumerable或IQueryable)的操作,使⽤延迟执⾏,⽽返回单⼀值的运算,使⽤⽴即执⾏。
IEnumerable是延迟执⾏的,当没有触发执⾏时,就不会进⾏任何运算。Select⽅法不会触发LINQ的执⾏。⼀些触发的⽅式是:foreach循环,ToList,ToArray,ToDictionary⽅法等

30…LINQ可视化⼯具简单介绍⼀下?

LINQPad⼯具是⼀个很好的LINQ查询可视化⼯具。它由Threading in C#和C# in a Nutshell的作者
Albahari编写,完全免费。它的下载地址是http://www.linqpad.net/
进⼊界⾯后,LINQPad可以连接到已经存在的数据库(不过就仅限微软的SQL Server系,如果要连接到其他类型的数据库则需要安装插件)。某种程度上可以代替SQL Management Studio,是使⽤SQLManagement Studio作为数据库管理软件的码农的强⼒⼯具,可以⽤于调试和性能优化(通过改善编译后的SQL规模)。
LINQPad⽀持使⽤SQL或C#语句(点标记或查询表达式)进⾏查询。你也可以通过点击橙⾊圈内的各种不同格式,看到查询表达式的各种不同表达⽅式:
Lambda:查询表达式的Lambda表达式版本,
SQL:由编译器转化成的SQL,通常这是我们最关⼼的部分,
IL:IL语⾔

31.LINQ to Object和LINQ to SQL有何区别?

LINQ to SQL可以将查询表达式转换为SQL语句,然后在数据库中执⾏。相⽐LINQ to Object,则是将查询表达式直接转化为Enumerable的⼀系列⽅法,最终在C#内部执⾏。LINQ to Object的数据源总是实现IEnumerable(所以不如叫做LINQ to IEnumerable),相对的,LINQ to SQL的数据源总是实现IQueryable并使⽤Queryable的扩展⽅法。将查询表达式转换为SQL语句并不保证⼀定可以成功。

32.除了EF,列举出你知道的ORM框架?

dapper EntityFramework、 EJB、Hibernate、IBATIS、TopLink、OJB

33.如何如何获取EF⽣成的Sql脚本?

1.可以调试起来通过SqlServerProfiler 来获取Sql
2.EF Dbcontext 注册⽇志事件输出⽇志查看Sql

34.在哪些类型额项⽬中你会选择EF? 为什么?

这个要结合EF的特点来说:EF主要是以⾯向对象的思想来做数据库数据操作,对Sql语句能⼒没什么要求,开发使⽤效率⾼!便于上⼿,⼀般来说,使⽤EF框架,肯定会⽐直接使⽤ADO.NET,消耗的时间多⼀些。 所以在⼀般企业级开发,管理型系统,对数据性能要求不是特别⾼的情况下,优先选择EF,这样可以⼤⼤的推进开发效率!如果像⼀些互联⽹项⽬中,对性能要求精度很⾼!可以另外做技术选型,选择原⽣ADO.NET。

35.请说明EF中映射实体对象的⼏种状态?

Detached:该实体未由上下⽂跟踪。刚使⽤新运算符或某个System.Data.Entity.DbSet Create ⽅法创建实体后,实体就处于此状态。
Unchanged:实体将由上下⽂跟踪并存在于数据库中,其属性值与数据库中的值相同。
Added:实体将由上下⽂跟踪,但是在数据库中还不存在。
Deleted:实体将由上下⽂跟踪并存在于数据库中,但是已被标记为在下次调⽤ SaveChanges 时从数据库中删除。
Modified:实体将由上下⽂跟踪并存在于数据库中,已修改其中的⼀些或所有属性值。

36.如果实体名称和数据库表名不⼀致,该如何处理?

实体名称和数据库表名称不⼀致:可以通过使⽤TableAttribute 特性;

37. 泛型的优点有哪些?

代码的可重⽤性。⽆需从基类型继承,⽆需重写成员。
扩展性好。
类型安全性提⾼。 泛型将类型安全的负担从你那⾥转移到编译器。 没有必要编写代码来测试正确的数据类型,因为它会在编译时强制执⾏。 降低了强制类型转换的必要性和运⾏时错误的可能性。
性能提⾼。泛型集合类型通常能更好地存储和操作值类型,因为⽆需对值类型进⾏装箱。

38…try {}⾥有⼀个return语句,那么紧跟在这个try后的finally {}⾥的code会不会被执⾏,什么时候被执⾏,在return前还是后?

会执⾏,在return前执⾏。

39…C# 中的异常类有哪些?

C# 异常是使⽤类来表示的,异常类主要是直接或间接地派⽣于System.Exception 类。
System.ApplicationException 和 System.SystemException 类是派⽣于 System.Exception 类的异常类。
System.ApplicationException 类⽀持由应⽤程序⽣成的异常,所以我们⾃⼰定义的异常都应派⽣⾃该类。
System.SystemException 类是所有预定义的系统异常的基类。
System.IO.IOException ⽤于处理 I/O 错误(读写⽂件)。
System.IndexOutOfRangeException ⽤于处理当⽅法指向超出范围的数组索引时⽣成的错误。
System.ArrayTypeMismatchException ⽤于处理当数组类型不匹配时⽣成的错误。
System.NullReferenceException ⽤于处理当依从⼀个空对象时⽣成的错误。
System.DivideByZeroException ⽤于处理当除以零时⽣成的错误。例如:100/0就会报这个错误。
System.InvalidCastException ⽤于处理在类型转换期间⽣成的错误。
System.OutOfMemoryException ⽤于处理空闲内存不⾜⽣成的错误。
System.StackOverflowException ⽤于处理栈溢出⽣成的错误。

40.泛型有哪些常⻅的约束?

泛型约束 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必须是引⽤类型,并且要有⼀个⽆参的构造函数(对于⼀个类型有多有约束,中间⽤逗号隔开)

41.Collection和Collections的区别?

Collection 是集合类的上级接⼝,Collections 是针对集合类的⼀个帮助类,它提供⼀系列静态⽅法来实现对各种集合的搜索,排序,线程安全化操作。

42.能⽤foreach 遍历访问的对象的要求?

需要实现IEnumerable接⼝或声明GetEnumerator⽅法的类型。

43.说出五个集合类?

List:泛型类;
Stack:堆栈,后进先出的访问各个元素
Dictionary<TKey, TValue>:字典类,key是区分⼤⼩写;value⽤于存储对应于key的值
HashSet:此集合类中不能有重复的⼦元素
SortedList<TKey, TValue>:排序列表,key是排好序的数组。

44.C#可否对内存进⾏直接的操作?

C#在Unsafe 模式下可以使⽤指针对内存进⾏操作, 但在托管模式下不可以使⽤指针。
1.在 Visual Studio 开发环境中设置/unsafe(启⽤不安全模式)编译器选项
打开项⽬的“属性”⻚。
单击“⽣成”属性⻚。
选中“允许不安全代码”复选框。
2.unsafe关键字表示不安全上下⽂,该上下⽂是任何涉及指针的操作所必需的
可以在类型或成员的声明中使⽤ unsafe修饰符。
因此,类型或成员的整个正⽂范围均被视为不安全上下⽂。例如,以下是⽤ unsafe 修饰符声明的⽅法:

unsafe static void FastCopy(byte[] src, byte[] dst, int count)
 {
    
    
 // Unsafe context: can use pointers here.
 }

不安全上下⽂的范围从参数列表扩展到⽅法的结尾,因此指针在以下参数列表中也可以使⽤:

unsafe static void FastCopy ( byte* ps, byte* pd, int count )
{
    
    ...}

还可以使⽤不安全块从⽽能够使⽤该块内的不安全代码。例如:

 unsafe
{
    
    
 // Unsafe context: can use pointers here.
}

若要编译不安全代码,必须指定 /unsafe编译器选项。⽆法通过公共语⾔运⾏库验证不安全代码。

45…HashMap和Hashtable区别?

Collection是集合类的上级接⼝,Collections是针对集合类的⼀个帮助类,它提供⼀系列静态⽅法来实现对各种集合的搜索,排序,线程安全化操作。

猜你喜欢

转载自blog.csdn.net/weixin_45091053/article/details/127147108