C#开发笔记
02、入门
03、进阶
04、架构
01、知识概念
01、基础语法
02、面向对象
03、集合、异常、泛型、LINQ、委托、EF
04、多线程
05、WPF
06、ASP.NET MVC
07、ASP.NET Core
08、ADO.NET、XML、HTTP、AJAX、WebService
09、常见的算法
10、数据库概念知识
11、数据库SQL查询(附建表语句)
00、高阶
05、U3D
01、基础
001、问的比较多的问题
06、前端开发
001、CSS基础
本文档使用 MrDoc 发布
-
+
首页
03、集合、异常、泛型、LINQ、委托、EF
#### 1. IList 接口与 List 的区别是什么? **IList 泛型接口是 Icollection 接口的子代,并且是所有非泛型列表的基接口。 Ilist 实现有三种类别:只读、固定大小、可变大小。 无法修改只读 Ilist。 固定大小的 Ilist 不允许添加或移除元素,但允许修改现有元素。 可变大小的 Ilist 允许添加、移除和修改元素。** **IList 是个接口,定义了一些操作方法这些方法要你自己去实现,当你只想使用接口的方法时,这种方式比较好.他不获取实现这个接口的类的其他方法和字段,有效的节省空间.** **List 是个类型 已经实现了 IList 定义的那些方法。** ```plain List List11 =new List (); ``` **是想创建一个 List,而且需要使用到 List 的功能,进行相关操作。** 而 ```plain IList IList11 =new List (); ``` **只是想创建一个基于接口 IList 的对象的实例,只是这个接口是由 List 实现的。所以它只是希望使用到 IList 接口规定的功能而已。** #### 2.泛型的主要约束和次要约束是什么? **当一个泛型参数没有任何约束时,它可以进行的操作和运算是非常有限的,因为不能对实参进行任何类型上的保证,这时候就需要用到泛型约束。泛型的约束分为:主要约束和次要约束,它们都使实参必须满足一定的规范,C#编译器在编译的过程中可以根据约束来检查所有泛型类型的实参并确保其满足约束条件。** (1)主要约束 **一个泛型参数至多拥有一个主要约束,主要约束可以是一个引用类型、class 或者 struct。如果指定一个引用类型(class),那么实参必须是该类型或者该类型的派生类型。相反,struct 则规定了实参必须是一个值类型。下面的代码展示了泛型参数主要约束:** ```plain 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 增加一个次要约束: ```plain public class ClassT3<T> where T : struct, IComparable { ...... } ``` #### 3. 如何把一个 array 复制到 arrayist 里? ```plain foreach( object arr in array) { arrayist.Add(arr); } ``` #### 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 方法。 ```plain 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#异常应该具有的信息和方法。值得注意的属性有:** ```plain public virtual string Message { get; }// 错误的信息,文字描述 public virtual string StackTrace { get; }// 发生异常的调用堆栈信息 public System.Reflection.MethodBase TargetSite { get; }//引发这个错误的方法 public Exception InnerException { get; }// 子异常 ``` #### 10. 如何创建一个自定义异常? **根据类继承原则和异常处理原则,我们可以使用以下方式来自定义一个类:** ```plain public class CustomException : Exception { } ``` #### 11. 利用 IEnumerable 实现斐波那契数列生成? ```plain 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 。** ```csharp 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.如何针对不同的异常进行捕捉? ```plain 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。→ 进行类型判断** ```plain 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 。→ 用于类型转型** ```plain 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。** ```plain 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. 什么事匿名方法? **匿名方法是用作委托的参数的一段代码。** ```plain //匿名方法,例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 表达式的结果也可能会随着外部变量变化而变化。** **如下面的例子:** ```plain 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 模型设计器修改这些模型之间对应关系。** **来自 **[https://blog.csdn.net/u011854789/article/details/72783902](https://blog.csdn.net/u011854789/article/details/72783902) 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。可变性有两种类型:协变和逆变。** **协变性:** **可以建立一个较为一般类型的变量,然后为其赋值,值是一个较为特殊类型的变量。例如:** ```plain 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 对象画等号。如果强行要实现的话,只能这么干:** ```plain string s = (string) new object(); ``` **但这样还是会在运行时出错。这也告诉我们,逆变性是很不正常的。** **泛型的协变与逆变:** **协变性和 out 关键字搭配使用,用于向调用者返回某项操作的值。例如下面的接口仅有一个方法,就是生产一个 T 类型的实例。那么我们可以传入一个特定类型。如我们可以将 IFactory 视为 IFactory。这也适用于 Food 的所有子类型。(即将其视为一个更一般类型的实现)** ```plain interface IFactory<T> { T CreateInstance(); } ``` **逆变性则相反,和 in 关键字搭配使用,指的是 API 将会消费值,而不是生产值。此时一般类型出现在参数中:** ```plain interface IPrint<T> { void Print(T value); } ``` **这意味着如果我们实现了 IPrint< Code >,我们就可以将其当做 IPrint< CsharpCode > 使用。(即将其视为一个更具体类型的实现)** **如果存在双向的传递,则什么也不会发生。这种类型是不变体(invariant)。** ```plain 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,从而形成多个互相不影响的迭代过程。** **在迭代时,只能前进不能后退。新的迭代不会记得之前迭代后值的任何变化。** #### 28.延迟执行 (Lazy Loading)是什么? **大部分 LINQ 语句是在最终结果的第一个元素被访问的时候(即在 foreach 中调用 MoveNext 方法)才真正开始运算的,这个特点称为延迟执行。一般来说,返回另外一个序列(通常为 IEnumerable 或 IQueryable)的操作,使用延迟执行,而返回单一值的运算,使用立即执行。** **IEnumerable 是延迟执行的,当没有触发执行时,就不会进行任何运算。Select 方法不会触发 LINQ 的执行。一些触发的方式是:foreach 循环,ToList,ToArray,ToDictionary 方法等** #### 29.LINQ 可视化工具简单介绍一下? **LINQPad 工具是一个很好的 LINQ 查询可视化工具。它由 Threading in C#和 C# in a Nutshell 的作者 Albahari 编写,完全免费。它的下载地址是 http://www.linqpad.net/** **进入界面后,LINQPad 可以连接到已经存在的数据库(不过就仅限微软的 SQL Server 系,如果要连接到其他类型的数据库则需要安装插件)。某种程度上可以代替 SQL Management Studio,是使用 SQL Management Studio 作为数据库管理软件的码农的强力工具,可以用于调试和性能优化(通过改善编译后的 SQL 规模)。** **LINQPad 支持使用 SQL 或 C#语句(点标记或查询表达式)进行查询。你也可以通过点击橙色圈内的各种不同格式,看到查询表达式的各种不同表达方式:** **Lambda:查询表达式的 Lambda 表达式版本,** SQL:由编译器转化成的 SQL,通常这是我们最关心的部分, IL:IL 语言 #### 29.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 语句并不保证一定可以成功。** #### 30.除了 EF,列举出你知道的 ORM 框架? **dapper EntityFramework、 EJB、Hibernate、IBATIS、TopLink、OJB** #### 31.如何如何获取 EF 生成的 Sql 脚本? **1.可以调试起来通过 SqlServerProfiler 来获取 Sql** **2.EF Dbcontext 注册日志事件输出日志查看 Sql** #### 32.在哪些类型额项目中你会选择 EF? 为什么? **这个要结合 EF 的特点来说:EF 主要是以面向对象的思想来做数据库数据操作,对 Sql 语句能力没什么要求,开发使用效率高!便于上手,一般来说,使用 EF 框架,肯定会比直接使用 ADO.NET,消耗的时间多一些。 所以在一般企业级开发,管理型系统,对数据性能要求不是特别高的情况下,优先选择 EF,这样可以大大的推进开发效率!如果像一些互联网项目中,对性能要求精度很高!可以另外做技术选型,选择原生 ADO.NET。** #### 33.请说明 EF 中映射实体对象的几种状态? **Detached:该实体未由上下文跟踪。刚使用新运算符或某个 System.Data.Entity.DbSet Create 方法创建实体后,实体就处于此状态。** **Unchanged:实体将由上下文跟踪并存在于数据库中,其属性值与数据库中的值相同。** **Added:实体将由上下文跟踪,但是在数据库中还不存在。** **Deleted:实体将由上下文跟踪并存在于数据库中,但是已被标记为在下次调用 SaveChanges 时从数据库中删除。** **Modified:实体将由上下文跟踪并存在于数据库中,已修改其中的一些或所有属性值。** #### 34.如果实体名称和数据库表名不一致,该如何处理? **实体名称和数据库表名称不一致:可以通过使用 TableAttribute 特性;** #### 35. 泛型的优点有哪些? **代码的可重用性。无需从基类型继承,无需重写成员。** **扩展性好。** **类型安全性提高。 泛型将类型安全的负担从你那里转移到编译器。 没有必要编写代码来测试正确的数据类型,因为它会在编译时强制执行。 降低了强制类型转换的必要性和运行时错误的可能性。** **性能提高。泛型集合类型通常能更好地存储和操作值类型,因为无需对值类型进行装箱。** #### 36.try {}里有一个 return 语句,那么紧跟在这个 try 后的 finally {}里的 code 会不会被执行,什么时候被执行,在 return 前还是后? **会执行,在 return 前执行。** #### 37.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 用于处理栈溢出生成的错误。** #### 38.泛型有哪些常见的约束? **泛型约束 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 必须是引用类型,并且要有一个无参的构造函数(对于一个类型有多有约束,中间用逗号隔开)** #### 39.Collection 和 Collections 的区别? **Collection 是集合类的上级接口,Collections 是针对集合类的一个帮助类,它提供一系列静态方法来实现对各种集合的搜索,排序,线程安全化操作。** #### 40.能用 foreach 遍历访问的对象的要求? **需要实现 IEnumerable 接口或声明 GetEnumerator 方法的类型。** #### 41.说出五个集合类? **List:泛型类;** **Stack:堆栈,后进先出的访问各个元素** **Dictionary<TKey, TValue>:字典类,key 是区分大小写;value 用于存储对应于 key 的值** **HashSet:此集合类中不能有重复的子元素** **SortedList<TKey, TValue>:排序列表,key 是排好序的数组。** #### 42.C#可否对内存进行直接的操作? **C#在 Unsafe 模式下可以使用指针对内存进行操作, 但在托管模式下不可以使用指针。** **1.在 Visual Studio 开发环境中设置/unsafe(启用不安全模式)编译器选项** 打开项目的“属性”页。 单击“生成”属性页。 选中“允许不安全代码”复选框。 **2.unsafe 关键字表示不安全上下文,该上下文是任何涉及指针的操作所必需的。** **可以在类型或成员的声明中使用 unsafe 修饰符。** **因此,类型或成员的整个正文范围均被视为不安全上下文。例如,以下是用 unsafe 修饰符声明的方法:** ```plain unsafe static void FastCopy(byte[] src, byte[] dst, int count) { // Unsafe context: can use pointers here. } ``` **不安全上下文的范围从参数列表扩展到方法的结尾,因此指针在以下参数列表中也可以使用:** ```plain unsafe static void FastCopy ( byte* ps, byte* pd, int count ) {...} ``` **还可以使用不安全块从而能够使用该块内的不安全代码。例如:** ```plain unsafe { // Unsafe context: can use pointers here. } ``` **若要编译不安全代码,必须指定 /unsafe 编译器选项。** 无法通过公共语言运行库验证不安全代码。 #### 43.HashMap 和 Hashtable 区别? **Collection 是集合类的上级接口,Collections 是针对集合类的一个帮助类,它提供一系列静态方法来实现对各种集合的搜索,排序,线程安全化操作。**
个人天使
2025年2月12日 17:23
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码