C#综合面试题(新手)
一、理论题
1、事务
事务执行一系列的数据库语句内容,要么一起成功要么一起回滚(撤销成功的语句)
四大特性:
①**原子性:**一起执行,
②**一致性:**数据库状态执行前后一致
③**持久性:**一旦成功永久保存在数据库中
④**隔离性:**并发事务彼此互不干扰
2、单例模式
是一种创建型设计模式,旨在确保一个类只有一个实例,并提供全局访问点以获取该实例。这在需要限制类的实例数量,确保全局状态一致性,或避免重复资源消耗的情况下非常有用。(类在全局只有一个实例,节省资源)
特点:
- 单一实例: 单例模式确保一个类只能有一个实例。该实例由类自己管理,并在需要时进行创建。
- 全局访问点: 单例模式提供一个全局访问方法,允许其他代码在任何时候获取该唯一实例。
四种常用的创建方式:
-
经典的懒汉式(Lazy Initialization): 在首次使用时创建实例。需要注意的是,多线程环境下可能引发并发问题,需要进行同步处理。
public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton GetInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
-
线程安全的懒汉式(Thread-Safe Lazy Initialization): 在多线程环境下保证线程安全,但可能会带来性能开销。
public class Singleton { private static Singleton instance; private static readonly object lockObject = new object(); private Singleton() { } public static Singleton GetInstance() { lock (lockObject) { if (instance == null) { instance = new Singleton(); } } return instance; } }
-
饿汉式(Eager Initialization): 在类加载时就创建实例,不存在多线程问题,但可能在程序启动时带来性能开销。
public class Singleton { private static readonly Singleton instance = new Singleton(); private Singleton() { } public static Singleton GetInstance() { return instance; } }
-
双重检查锁定(Double-Check Locking): 在多线程环境下保证线程安全,同时尽量减少锁的使用,提高性能。
public class Singleton
{
private static volatile Singleton instance;
private static readonly object lockObject = new object();
private Singleton() { }
public static Singleton GetInstance()
{
if (instance == null)
{
lock (lockObject)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
3、委托和事件
①委托是一种类型,它可以用来引用一个或多个方法。它可以被认为是一个方法的指针,允许你将方法作为参数传递、存储在数据结构中或从方法中返回。委托可以用于实现回调机制、事件处理等。
delegate returnType DelegateName(parameters);
②事件是一种特殊类型的委托,它提供了一种更安全、更规范的方式来实现订阅和通知模式。事件允许对象注册为事件的监听者,并在事件发生时得到通知。
using System;
class Program
{
public delegate void MyEventHandler(string message);
public class MyEventPublisher
{
public event MyEventHandler MyEvent;
public void RaiseEvent(string message)
{
MyEvent?.Invoke(message);
}
}
public class MyEventListener
{
public void HandleEvent(string message)
{
Console.WriteLine("Event handled: " + message);
}
}
static void Main()
{
MyEventPublisher publisher = new MyEventPublisher();
MyEventListener listener = new MyEventListener();
publisher.MyEvent += listener.HandleEvent;
publisher.RaiseEvent("Hello from the event!");
publisher.MyEvent -= listener.HandleEvent; // 取消事件订阅
publisher.RaiseEvent("This won't be handled.");
Console.ReadLine();
}
}
二、C#基础题
1、static
定义为静态字段,可以在不实例化类的情况下调用该字段,在类被初始化的时候会生成该字段,在整个应用程序生命周期下都存在
2、C#类的作用域
①public
:公共作用域,在该命名空间或程序集的外部也可见,其他命名空间或程序集可以通过引用和使用该类
②Internal
:内部作用域,将在同一命名空间内的其他文件中可见,其他命名空间或程序集不可以通过引用和使用该类
③Protected
:受保护的,类的派生类可以访问这些受保护成员,但其他非派生类的代码无法访问
④private
:私有的,只能在同一个类的内部访问,外部代码无法直接访问这些私有成员
3、线程实现
①使用ThreadPool
的ThreadPool.QueueUserWorkItem(WorkerMethod)
;实现多线程
using System;
using System.Threading;
class Program
{
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(WorkerMethod);
// 主线程继续执行其他任务
Thread.Sleep(2000); // 等待足够时间,使子线程有机会执行
}
static void WorkerMethod(object state)
{
Console.WriteLine("Worker thread from ThreadPool is starting...");
Thread.Sleep(2000);
Console.WriteLine("Worker thread from ThreadPool finished.");
}
}
②实例化Task
使用Task.Run(WorkerMethod)
using System;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Task task = Task.Run(WorkerMethod);
// 主线程继续执行其他任务
task.Wait(); // 等待任务完成
}
static void WorkerMethod()
{
Console.WriteLine("Worker task is starting...");
Task.Delay(2000).Wait();
Console.WriteLine("Worker task finished.");
}
}
③实例化Thread
使用 thread.Start()
;
using System;
using System.Threading;
class Program
{
static void Main(string[] args)
{
Thread thread = new Thread(WorkerMethod);
thread.Start();
// 主线程继续执行其他任务
thread.Join(); // 等待子线程完成
}
static void WorkerMethod()
{
Console.WriteLine("Worker thread is starting...");
Thread.Sleep(2000);
Console.WriteLine("Worker thread finished.");
}
}
④异步方法
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
await WorkerMethodAsync();
// 主线程继续执行其他任务
}
static async Task WorkerMethodAsync()
{
Console.WriteLine("Worker method is starting...");
await Task.Delay(2000);
Console.WriteLine("Worker method finished.");
}
}
4、如何引用C++的dll
文件
-
创建C++ DLL: 首先,你需要创建一个C++的动态链接库(DLL)。确保在创建DLL时,使用了与C#兼容的调用约定,通常使用
__declspec(dllexport)
来导出函数和类。 -
编译C++ DLL: 将C++代码编译为DLL文件。你可能需要使用特定的编译选项和链接库,以确保生成与C#兼容的DLL。
-
在C#中创建项目: 打开Visual Studio(或其他C#开发环境),创建一个新的C#项目,例如Class Library,Console Application等,用于在C#中调用C++的DLL。
-
添加DLL引用: 将生成的C++ DLL文件复制到C#项目的目录中,然后在C#项目中添加对该DLL文件的引用。在Solution Explorer中,右键点击项目,选择"Add" -> “Reference”,然后浏览并选择你的DLL文件。
-
使用DllImport特性: 在C#代码中,使用
DllImport
特性来引入C++ DLL中的函数。这允许你在C#代码中调用C++ DLL中的函数。示例如下:using System; using System.Runtime.InteropServices; public class Program { // 声明引用的DLL中的函数 [DllImport("YourCppDll.dll")] public static extern int YourCppFunction(int parameter); public static void Main() { int result = YourCppFunction(42); Console.WriteLine("Result from C++ DLL: " + result); } }
-
编译并运行: 编译并运行C#项目。确保在运行时,C++的DLL文件与生成的C#可执行文件位于同一目录中,以便正确加载。
三、框架技术题
1、asp.net特点
(1)服务器端技术: ASP.NET 是一种服务器端技术,意味着 Web 应用程序的逻辑和处理发生在服务器上,然后将生成的 HTML 响应发送到客户端浏览器。
(2)面向对象编程: ASP.NET 支持面向对象编程的特性,可以使用 C#、VB.NET 等编程语言编写代码。
(3)Web Forms 和 MVC: ASP.NET 提供了两种主要的编程模型:Web Forms 和 MVC(Model-View-Controller)。Web Forms 强调了事件驱动的编程,而 MVC 更加注重分离应用的不同层,如数据处理、逻辑和视图。
(4)视图引擎: ASP.NET 支持多种视图引擎,允许开发者将数据和界面分离,以便更好地管理代码和界面。
(5)数据访问技术: ASP.NET 提供了多种数据访问技术,包括 ADO.NET、Entity Framework 等,用于连接数据库并执行数据操作。
(6)控件模型: ASP.NET 提供了丰富的服务器端控件,使开发者能够轻松地构建用户界面,从简单的按钮和文本框到复杂的数据表格。
(7)安全性: ASP.NET 提供了多种安全性功能,包括用户认证、授权、加密等,以保护应用程序的数据和功能。
(8)性能优化: ASP.NET 具有一些性能优化的特性,如输出缓存、数据缓存等,以提高应用程序的响应速度。
(9)跨平台: 最新版本的 ASP.NET(ASP.NET Core)支持跨平台开发,可以在 Windows、Linux 和 macOS 等操作系统上运行。
(10)集成开发环境: Microsoft Visual Studio 是一个强大的集成开发环境,用于开发 ASP.NET 应用程序,提供了代码编辑、调试、测试等功能。
2、MVC
MVC:M是model,V是View、c是controller
(1)Model
(模型): 模型表示应用程序的数据和业务逻辑。它负责处理数据的获取、存储、验证和处理,以及实现业务规则。模型并不关心数据如何呈现给用户或从用户接收什么输入。
(2)View
(视图): 视图是用户界面的呈现部分,负责展示数据给用户。它通常是用户可以看到和与之交互的部分。视图不包含业务逻辑,只负责将模型数据呈现出来。
(3)Controller
(控制器): 控制器负责处理用户的请求,协调模型和视图之间的交互。它接收来自用户的输入,处理业务逻辑,更新模型,然后选择适当的视图来展示结果。
3、MVVM
(1)Model
(模型): 模型表示应用程序的数据和业务逻辑,与其他架构模式中的模型类似。它负责管理数据的状态、获取、验证和处理。
(2)View
(视图): 视图是用户界面的呈现部分,通常是 HTML、XML 或其他界面描述语言。在 MVVM 中,视图不应包含业务逻辑,只关注展示数据和用户交互。
(3)ViewModel
(视图模型): 视图模型是连接模型和视图的桥梁,负责将模型的数据适配成视图所需的格式,以及处理视图中的用户交互。视图模型通常包含了展示逻辑、格式化数据和处理命令。
四、数据库题
1、group by和order by
①**group by
**一般配合聚合函数(SUM、AVG、COUNT)一起使用,用于分组查询。
②**order by
** 用于排序,ASC表示降序、DESC表示升序。
2、数据库函数
①聚合函数: 用于对一组值执行计算,并返回一个单一的结果。
SUM
:计算列中值的总和。AVG
:计算列中值的平均值。COUNT
:计算行数或特定列的非空值数量。MAX
:找到列中的最大值。MIN
:找到列中的最小值
②**字符串函数:**用于处理文本数据。
CONCAT
:连接两个或多个字符串。SUBSTRING
:提取字符串的子串。LENGTH
或LEN
:获取字符串的长度。UPPER
或UCASE
:将字符串转换为大写。LOWER
或LCASE
:将字符串转换为小写。
③**日期和时间函数(Date and Time Functions): **用于处理日期和时间数据。
NOW
:获取当前日期和时间。DATE
:提取日期部分。TIME
:提取时间部分。YEAR
、MONTH
、DAY
:提取年、月、日。DATEDIFF
:计算日期之间的差值。
④逻辑函数(Logical Functions): 用于执行逻辑操作。
IF
、CASE
:条件语句,根据条件返回不同的值。AND
、OR
、NOT
:逻辑运算符。
⑤数学函数(Mathematical Functions): 用于数值计算。
ABS
:取绝对值。ROUND
:四舍五入。CEIL
或CEILING
:向上取整。FLOOR
:向下取整。POWER
、SQRT
:计算幂次和平方根。
⑥类型转换函数(Type Conversion Functions): 用于在不同数据类型之间进行转换。
CAST
:将一个数据类型转换为另一个。CONVERT
:将一个数据类型转换为另一个,通常在不同数据库系统中有不同的语法。
3、存储过程
优点:
- 性能优化: 存储过程可以在数据库服务器上进行预编译,提高查询性能。
- 代码重用: 可以将常用的查询逻辑封装在存储过程中,从而减少代码重复。
- 安全性: 存储过程可以限制用户对数据库的直接访问,通过存储过程来控制数据的访问。
- 逻辑封装: 存储过程可以实现复杂的逻辑操作,比如事务处理、数据处理和转换等。
- 简化客户端代码: 客户端代码只需要调用存储过程,而无需直接编写复杂的 SQL 查询。
示例:
-- 创建存储过程
CREATE PROCEDURE GetCustomerCountByCity
@CityName NVARCHAR(50)
AS
BEGIN
SELECT COUNT(*) AS CustomerCount
FROM Customers
WHERE City = @CityName;
END;
-- 调用存储过程并传递参数
DECLARE @Result INT;
EXEC GetCustomerCountByCity @CityName = 'New York', @Result OUTPUT;
-- 显示结果
PRINT 'Customer count in New York: ' + CAST(@Result AS NVARCHAR);
4、索引
索引(Index)是一种数据结构,用于加速数据库表中数据的检索操作。通过创建索引,数据库可以更快地定位和访问表中的特定数据行,而不必进行全表扫描。索引通常基于表中的一个或多个列,提高了查询效率,但同时也会占用一定的存储空间并对写操作(插入、更新、删除)产生一定的影响。
(1)索引类型:
①唯一索引(Unique Index): 唯一索引要求索引列中的每个值都是唯一的,用于确保数据的唯一性。例如,一个表中的主键通常会自动创建唯一索引。
②聚集索引(Clustered Index): 聚集索引决定了数据在磁盘上的物理存储顺序。每个表只能有一个聚集索引,通常是主键索引。表的数据按照聚集索引的顺序存储,因此聚集索引对于范围查询效率较高。
③非聚集索引(Non-clustered Index): 非聚集索引不会改变数据在磁盘上的物理存储顺序,而是创建一个单独的索引结构来加速数据的检索。一个表可以有多个非聚集索引。
(2)SQL SERVER索引实例:
①创建一个普通非聚集索引
CREATE NONCLUSTERED INDEX idx_FirstName ON Customers (FirstName);
②创建一个唯一非聚集索引:
CREATE UNIQUE NONCLUSTERED INDEX idx_CustomerID_unique ON Customers (CustomerID);
③创建一个聚集索引(一般用于主键):
CREATE CLUSTERED INDEX idx_CustomerID ON Customers (CustomerID);
(3)MYSQL索引实例:
①创建一个普通索引:
CREATE INDEX idx_username ON users (username);
②创建一个唯一索引:
CREATE UNIQUE INDEX idx_email_unique ON users (email);
③创建一个组合索引:
CREATE INDEX idx_username_email ON users (username, email);
5、数据类型
①整型:
INT
:常用、4bit;SMALLINT
:小范围整型、2bit、-32,768 到 32,767;TINYINT
:1bit、0-255;- BIGINT`:大范围整型、8bit。
②浮点数:
float(n)
:单精度,n表示有效位数;REAL
:双精度浮点数。DOUBLE
或DOUBLE PRECISION
:双精度浮点数。
③定点数:
DECIMAL(p, s)
或 NUMERIC(p, s)
:精确的定点数,其中 p
表示总位数,s
表示小数位数。
④字符串类型:
CHAR(n)
:固定长度的字符,其中n
表示字符数;VARCHAR(n)
:可变长度的字符,其中n
表示最大字符数;TEXT
:存储大文本块的类型;NCHAR(n)
:用于存储 Unicode 字符的固定长度字符串;NVARCHAR(n)
:用于存储 Unicode 字符的可变长度字符串;NTEXT
:存储大 Unicode 文本块的类型。ENUM
:用于存储从预定义选项中选择的值。SET
:用于存储多个从预定义选项中选择的值。
⑤日期与时间型(Date and Time Types):
DATE
:仅存储日期。TIME
:仅存储时间。DATETIME
或DATETIME2
:同时存储日期和时间。SMALLDATETIME
:较小范围的日期和时间。TIMESTAMP
:用于记录日期和时间,通常用于记录数据修改时间。YEAR
:用于存储年份。
⑥布尔型(Boolean Type):
- SQL Server 本身没有内置的布尔数据类型,通常使用
BIT
数据类型,其中 0 表示假,1 表示真。 - MySQL 中没有内置的布尔数据类型,通常使用
TINYINT
或ENUM
来模拟布尔值,其中 0 表示假,1 表示真。
⑦二进制型(Binary Types):
BINARY(n)
:固定长度的二进制数据。VARBINARY(n)
:可变长度的二进制数据。IMAGE
:用于存储大二进制块的类型。BLOB
:用于存储大二进制块的类型。
⑧JSON 和 XML 型:
JSON
:用于存储 JSON 格式的数据。XML
:用于存储 XML 格式的数据。
⑨自定义类型(User-Defined Types):
- SQL Server 支持创建自定义数据类型。
- MySQL 支持创建自定义数据类型。
⑩空间数据类型(Spatial Data Types):
- MySQL 支持存储和处理地理空间数据,如点、线、多边形等。
五、数据结构题
1、冒泡排序
public static void Main(string[] args){
int[] numbers={1,2,3,4,5,6,7,8,9}
for(int i=0;i<numbers.length;i++){
for(int j=i;j<i;j++){
if(numbers[i]<numbers[j]){
int num=numbers[i];
numbers[i]=numbers[j];
numbers[j]=num;
}
}
}
foreach(var num in numbers){
Console.WriteLine(num);
}
}
2、递归排序
static int Factorial(int n)
{
// 基本情况:阶乘的定义是0的阶乘为1,1的阶乘为1
if (n == 0 || n == 1)
{
return 1;
}
else
{
// 递归调用:n的阶乘等于 n * (n - 1) 的阶乘
return n * Factorial(n - 1);
}
}
static void Main()
{
int number = 5;
int result = Factorial(number);
Console.WriteLine($"Factorial of {number} is {result}");
}
六、前端技术题
1、HTTP协议工作原理
- 客户端-服务器模型: HTTP 是基于客户端-服务器模型的,客户端发送请求,服务器响应请求并返回数据。
- 请求-响应模型: 客户端发送一个 HTTP 请求给服务器,服务器处理请求并返回一个 HTTP 响应,其中包含请求的资源或错误信息。
- 无连接: 每个请求和响应都是独立的,服务器不会保存客户端的状态信息,这种特性称为无状态性。
- 无状态: HTTP 协议本身是无状态的,但通过使用 Cookie、Session 和其他机制,可以实现有状态的会话。
- 支持多媒体类型: HTTP 支持传输各种类型的数据,包括文本、图像、音频、视频等。
- URL(Uniform Resource Locator): URL 用于唯一标识 Web 上的资源。HTTP 请求使用 URL 来指定要请求的资源的位置。
- 请求方法: HTTP 定义了多种请求方法,如 GET、POST、PUT、DELETE 等,用于指定请求的操作类型。
- 状态码: HTTP 响应中包含状态码,用于表示请求的处理结果,例如 200 表示成功,404 表示未找到等。
- 报文: HTTP 请求和响应以报文的形式传输,包含请求头、请求体、响应头和响应体等部分。
- 持久连接: 为了减少连接的开销,HTTP 可以使用持久连接(Keep-Alive)来在一个连接上传输多个请求和响应。
- 安全性: HTTPS(HTTP Secure)是在 HTTP 上添加了安全性的协议,使用 SSL/TLS 加密传输数据,确保通信的机密性和完整性
2、JSON格式类型
- 对象(Object): 使用大括号
{}
包围,包含一系列键值对,每个键值对之间用逗号,
分隔。键是字符串,值可以是字符串、数字、布尔值、对象、数组等。 - 数组(Array): 使用方括号
[]
包围,包含一系列值,每个值之间用逗号,
分隔。值可以是字符串、数字、布尔值、对象、数组等。 - 字符串(String): 使用双引号
"
包围,表示文本数据。 - 数字(Number): 表示整数或浮点数。
- 布尔值(Boolean): 表示
true
或false
。 - 空值(null): 表示空值。
七、中间件技术题
1、EF和ado.net
①ado.net是原生的数据库交互技术,常用类:SqlConnection
、SqlCommand
、SqlDataReader
,实例:
using System;
using System.Data.SqlClient;
class Program
{
static void Main(string[] args)
{
string connectionString = "Data Source=ServerName;Initial Catalog=DatabaseName;User ID=UserName;Password=Password";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string sql = "SELECT FirstName, LastName FROM Customers";
SqlCommand command = new SqlCommand(sql, connection);
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
string firstName = reader["FirstName"].ToString();
string lastName = reader["LastName"].ToString();
Console.WriteLine($"Name: {firstName} {lastName}");
}
}
}
}
}
②EF是一个对象关系映射(ORM)框架,用于在 .NET 应用程序中实现对象和数据库之间的映射。它允许开发者使用面向对象的方式来操作数据库,而无需直接编写 SQL 查询语句。EF 提供了一个抽象层,使开发者可以通过 C# 或 VB.NET 代码来查询、插入、更新和删除数据,从而简化了数据访问层的开发。步骤:
- 安装Entity Framework: 在项目中安装Entity Framework的NuGet包。您可以使用Visual Studio的包管理器控制台来执行此操作,或者在项目文件中手动添加相关的NuGet依赖。
- 创建数据模型: 使用Entity Framework,您需要创建数据模型,通常是用于表示数据库中表的类。这些类通常称为"实体"(
Entities
)。您可以手动创建这些类,也可以使用Entity Framework的工具自动生成这些类。 - 配置数据库连接: 在应用程序的配置文件中,配置数据库连接字符串,以便Entity Framework知道如何连接到数据库。
- 创建
DbContext
:DbContext
是Entity Framework中的核心类,它表示数据库上下文。您需要创建一个继承自DbContext
的类,并将实体类添加到DbContext
中。 - 进行CRUD操作: 使用
DbContext
可以执行各种数据库操作,如创建(Create)、读取(Read)、更新(Update)和删除(Delete)数据。您可以通过对实体对象进行操作,然后调用DbContext
的相应方法来实现这些操作。
2、linq
表达式关键词
from
: 用于指定数据源,可以是集合、数组、数据库表等。where
: 用于筛选满足指定条件的数据项。select
: 用于选择从数据源中提取的数据项,可以进行数据变换和投影。orderby
: 用于对结果进行排序。group
: 用于将结果分组。join
: 用于在多个数据源之间执行联接操作。let
: 用于定义一个中间变量,可以在查询的其他部分使用。in
: 在查询表达式中用于指定要查询的数据源。on
: 用于在联接操作中指定联接条件。equals
: 用于在联接操作中指定等值比较条件。by
: 在group子句中用于指定分组键。ascending
: 在orderby
子句中用于指定升序排序。descending
: 在orderby
子句中用于指定降序排序。into
: 用于将一个查询的结果引入一个新的范围。join into
: 在联接操作中用于将联接的结果引入一个新的范围。
linq
示例:
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var evenNumbers = from number in numbers
where number % 2 == 0
select number;
foreach (var number in evenNumbers)
{
Console.WriteLine(number);
}
}
}
3、Lambda 表达式
(parameters) => expression_or_statement