C#面试题及答案 (2025)
C# 面试题及答案,适合初学者和有2/3/5/10年经验的开发人员
以下是 C# 面试题及答案,适合初学者以及有 5 或 10 年经验的候选人,帮助他们找到梦想的工作。
1) 什么是 C#?
C# 是一种面向对象的、类型安全的、托管的语言,它由 .Net 框架编译以生成 Microsoft 中间语言。
2) 举例说明 C# 中的注释类型
单行注释
示例
//This is a single line comment
ii. 多行注释 (/* */)
示例
/*This is a multiple line comment We are in line 2 Last line of comment*/
iii. XML 注释 (///)。
示例
/// summary; /// Set error message for multilingual language. /// summary
3) 是否可以执行多个 catch 块?
不可以,不能执行多个同类型的 catch 块。一旦执行了正确的 catch 代码,控制权就会转移到 finally 块,然后执行 finally 块之后的代码。
4) public、static 和 void 有什么区别?
Public 声明的变量或方法可以在应用程序的任何地方访问。Static 声明的变量或方法无需创建类的实例即可全局访问。静态成员默认情况下不是全局可访问的,它取决于所使用的访问修饰符的类型。编译器将方法的地址存储为入口点,并使用此信息在创建任何对象之前开始执行。而 Void 是一个类型修饰符,表示该方法或变量不返回值。
C# 面试题
5) 什么是对象?
对象是类的实例,通过它我们可以访问该类的方法。“New”关键字用于创建对象。在内存中创建对象的类将包含该类的方法、变量和行为的信息。
6) 定义构造函数
构造函数是类中的一个成员函数,其名称与类相同。每当创建类对象时,构造函数都会自动调用。它在初始化类时构造数据成员的值。
7) 什么是交错数组?
数组元素是数组类型的数组称为交错数组。元素可以具有不同的维度和大小。我们也可以称交错数组为数组的数组。
8) ref 和 out 参数之间有什么区别?
作为 ref 传递的参数在传递给方法之前必须初始化,而 out 参数在传递给方法之前不需要初始化。
9) C# 中的 'using' 语句有什么用?
'using' 块用于获取一个资源并处理它,然后在执行完块后自动释放它。
10) 什么是序列化?
当我们想通过网络传输对象时,必须将对象转换为字节流。将对象转换为字节流的过程称为序列化。要使对象可序列化,它应该实现 ISerialize 接口。反序列化是从字节流创建对象的逆过程。
11) 可以在静态方法中使用 "this" 命令吗?
不能在静态方法中使用 'This',因为我们只能在静态方法中使用静态变量/方法。
12) constants 和 read-only 有什么区别?
常量变量在编译时声明和初始化。之后不能更改其值。Read-only 仅在运行时要为变量赋值时使用。
13) 什么是接口类?举个例子
接口是一个抽象类,它只有公共的抽象方法,并且方法只有声明而没有定义。这些抽象方法必须在继承的类中实现。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DemoApplication { interface Guru99Interface { void SetTutorial(int pID, string pName); String GetTutorial(); } class Guru99Tutorial : Guru99Interface { protected int TutorialID; protected string TutorialName; public void SetTutorial(int pID, string pName) { TutorialID = pID; TutorialName = pName; } public String GetTutorial() { return TutorialName; } static void Main(string[] args) { Guru99Tutorial pTutor = new Guru99Tutorial(); pTutor.SetTutorial(1,".Net by Guru99"); Console.WriteLine(pTutor.GetTutorial()); Console.ReadKey(); } } }
14) 什么是值类型和引用类型?
值类型在其自身内存空间中保存数据值。例如
int a = 30;
引用类型存储存储值的对象地址。它是指向另一内存位置的指针。
string b = "Hello Guru99!!";
15) 什么是自定义控件和用户控件?
自定义控件是作为编译代码(Dlls)生成的控件,它们更易于使用,并且可以添加到工具箱中。开发人员可以将在工具箱中的控件拖放到他们的 Web 窗体上。属性可以在设计时设置。我们可以轻松地将自定义控件添加到多个应用程序(如果是共享 Dll)。所以,如果它们是私有的,我们可以将 Dll 复制到 Web 应用程序的 bin 目录,然后添加引用并使用它们。
用户控件非常类似于 ASP 的 include 文件,并且易于创建。用户控件不能放在工具箱中并从中拖放。它们有自己的设计和代码隐藏。用户控件的文件扩展名为 ascx。
16) C# 中的 sealed 类是什么?
当我们想限制类被继承时,我们创建 sealed 类。Sealed 修饰符用于防止派生自某个类。如果我们强制指定一个 sealed 类作为基类,则会发生编译时错误。
17) 什么是方法重载?
方法重载是在同一个类中创建多个同名但具有唯一签名的类。当我们编译时,编译器使用重载解析来确定要调用的特定方法。
18) Array 和 ArrayList 有什么区别?
在数组中,我们只能拥有相同类型的项。与 ArrayList 相比,数组的大小是固定的。ArrayList 类似于数组,但它没有固定的大小。
19) 私有的虚方法可以被重写吗?
不可以,因为它们在类外部无法访问。
20) 描述可访问性修饰符 "protected internal"。
Protected Internal 变量/方法可在同一程序集内访问,也可从派生自此父类的类中访问。
21) System.String 和 System.Text.StringBuilder 类之间有什么区别?
System.String 是不可变的。当我们修改字符串变量的值时,会为新值分配新的内存,并释放先前的内存分配。System.StringBuilder 的设计理念是支持可变字符串,可以在不为修改后的字符串分配单独内存位置的情况下执行各种操作。
22) System.Array.CopyTo() 和 System.Array.Clone() 之间有什么区别?
使用 Clone()
方法,我们创建了一个包含原始数组中所有元素的新数组对象,并使用 CopyTo()
方法。现有数组的所有元素都复制到另一个现有数组中。这两种方法都执行浅拷贝。
23) 如何按降序对数组元素进行排序?
使用 Sort()
方法,然后使用 Reverse()
方法。
24) 写出 C# 中捕获异常的语法
要捕获异常,我们使用 try-catch 块。Catch 块可以具有 System.Exception 类型的参数。
例如
try { GetAllData(); } catch (Exception ex) { }
在上面的示例中,我们可以从 catch 语句中省略参数。
25) 接口和抽象类有什么区别?
接口的所有方法只有声明而没有定义。在抽象类中,我们可以有一些具体的方法。在接口类中,所有方法都是公共的。抽象类可能具有私有方法。
26) Finalize() 和 Dispose() 方法有什么区别?
Dispose()
在我们想让对象释放任何非托管资源时被调用。另一方面,Finalize()
用于相同的目的,但它不保证对象的垃圾回收。
27) 什么是循环引用?
循环引用是指两个或多个资源相互依赖,导致锁定状态并使资源无法使用的情景。
28) C#.NET 中的泛型是什么?
泛型用于创建可重用代码类,以减少代码冗余,提高类型安全性和性能。使用泛型,我们可以创建集合类。要创建泛型集合,应使用 System.Collections.Generic 命名空间,而不是 System.Collections 命名空间中的 ArrayList 等类。泛型促进了参数化类型的用法。
29) .NET 中的对象池是什么?
对象池是一个包含已准备好使用的对象的容器。它跟踪当前正在使用的对象,以及池中的对象总数。这减少了创建和重新创建对象的开销。
30) 列出 .NET 中常用的异常类型
ArgumentException, ArgumentNullException, ArgumentOutOfRangeException, ArithmeticException, DivideByZeroException, OverflowException, IndexOutOfRangeException, InvalidCastException, InvalidOperationException, IOEndOfStreamException, NullReferenceException, OutOfMemoryException, StackOverflowException 等。
31) 什么是自定义异常?
有时会遇到需要根据用户要求进行处理的错误。自定义异常用于这些情况,是用户定义的异常。
32) 什么是委托?
委托与 C++ 中的函数指针相同,但唯一区别在于它们是类型安全的,不像函数指针。委托是必需的,因为它们可用于编写更通用的类型安全函数。
33) 如何在 C# 中将一个类继承到另一个类?
冒号用作 C# 中的继承运算符。只需放置一个冒号,然后是类名。
public class DerivedClass : BaseClass
34) .NET 中所有类都派生自哪个基类?
System.Object
35) 方法重写和方法重载有什么区别?
在方法重写中,我们在派生类中更改方法定义,从而改变了方法的行为。方法重载是在同一类中创建具有相同名称但签名不同的方法。
36) 方法可以有哪些不同的重载方式?
方法可以通过参数的不同数据类型、参数的不同顺序以及参数的不同数量来重载。
37) 为什么不能为接口内的函数指定可访问性修饰符?
在接口中,我们有不包含方法定义的虚方法。所有方法都将由派生类重写。因此,它们都是公共的。
38) 如何设置一个类可以被继承,但阻止其方法被重写?
将类声明为 public,并将方法声明为 sealed 以阻止其被重写。
39) 如果继承的接口具有冲突的方法名会怎样?
实现取决于您,因为方法在您自己的类中。当来自不同接口的方法需要不同的数据时,可能会出现问题,但就编译器而言,您没问题。
40) Struct 和 Class 有什么区别?
Struct 是值类型变量,而 Class 是引用类型。Struct 存储在堆上,会产生额外的开销,但检索速度更快。Struct 不能被继承。
41) 如何在 .Net 中使用可空类型?
值类型可以取其正常值或 null 值。这些类型称为可空类型。
Int? someID = null; If(someID.HasVAlue) { }
42) 如何用非默认值创建数组?
我们可以使用 Enumerable.Repeat 创建一个带有非默认值的数组。
43) C# 中的 "is" 和 "as" 运算符有什么区别?
"is" 运算符用于检查对象与给定类型的兼容性,并返回布尔结果。
"as" 运算符用于将对象转换为类型或类。
44) 什么是多播委托?
具有多个处理程序分配给它的委托称为多播委托。每个处理程序都分配给一个方法。
45) C# .NET 中的索引器是什么?
索引器被称为 C# 中的智能 数组。它允许类实例以与数组相同的方式进行索引。
例如
public int this[int index] // Indexer declaration
46) .NET 中 "throw" 和 "throw ex" 有什么区别?
"Throw" 语句保留原始错误堆栈,而 "throw ex" 具有从其抛出点的堆栈跟踪。始终建议使用 "throw",因为它提供了更准确的错误信息。
47) 什么是 C# 属性及其重要性?
C# 为开发人员提供了一种在特定实体(例如类、方法等)上定义声明性标记的方式,称为属性。属性信息可以在运行时使用反射检索。
48) 如何在 C# 中实现单例设计模式?
在单例模式中,一个类只能有一个实例,并提供全局访问点。
例如
Public sealed class Singleton { Private static readonly Singleton _instance = new Singleton(); }
49) DirectCast 和 Ctype 有什么区别?
DirectCast 用于转换对象的类型,该对象的运行时类型需要与 DirectCast 中指定的类型相同。
Ctype 用于转换,其中表达式和类型之间定义了转换。
50) C# 代码是托管代码还是非托管代码?
C# 是托管代码,因为通用语言运行时可以将 C# 代码编译成中间语言。
51) 什么是控制台应用程序?
控制台应用程序是在 Windows 命令提示符中运行的应用程序。对于任何 初学者 .Net,构建控制台应用程序是开始的理想第一步。
52) 提供一个移除队列中元素的示例
Dequeue 方法用于从队列中移除元素。
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DemoApplication { class Program { static void Main(string[] args) { Queue qt = new Queue(); qt.Enqueue(1); qt.Enqueue(2); qt.Enqueue(3); foreach (Object obj in qt) { Console.WriteLine(obj); } Console.WriteLine(); Console.WriteLine(); Console.WriteLine("The number of elements in the Queue " + qt.Count); Console.WriteLine("Does the Queue contain " + qt.Contains(3)); Console.ReadKey(); } } }
这些面试问题也将有助于您的口试