C# 面试题基础部分类型与引用类型的区别
值类型直接存储数据(如 intstruct),分配在栈上;引用类型存储数据地址(如 classstring),数据在堆中,栈上存引用。值类型复制时创建新副本,引用类型复制仅复制引用。

装箱与拆箱
装箱将值类型转换为 object 或接口类型,涉及堆内存分配;拆箱将对象转回值类型,需显式类型转换。频繁操作影响性能。
示例代码:

int i = 123;
object o = i; // 装箱
int j = (int)o; // 拆箱

readonlyconst 的区别
const 是编译时常量,必须初始化且值不可变;readonly 是运行时常量,可在声明或构造函数中初始化,适用于实例级别。


C# 面向对象相关

抽象类与接口的区别
抽象类可包含实现代码和字段,支持单继承;接口仅定义契约,无实现,支持多继承。C# 8.0 后接口可包含默认实现。

虚方法与抽象方法
虚方法在基类有默认实现,派生类可重写;抽象方法无实现,派生类必须重写。抽象方法只能存在于抽象类中。

sealed 关键字作用
修饰类时禁止被继承;修饰方法时禁止派生类重写该方法。


多线程与异步编程

TaskThread 的区别
Thread 是低层级线程操作;Task 基于线程池,支持异步/等待模式(async/await),资源利用更高效。

async/await 工作原理
await 释放当前线程,等待任务完成后恢复上下文。编译器将异步方法转换为状态机,避免阻塞主线程。
示例代码:

async Task<string> FetchDataAsync() {
    return await HttpClient.GetStringAsync("url");
}

线程同步机制

  • lock:简单互斥锁。
  • Monitor:类似 lock,支持超时控制。
  • Semaphore:限制并发访问数量。
  • Mutex:跨进程同步。

内存管理与垃圾回收

GC 工作原理
分代回收(0/1/2代),短期对象在Gen0频繁回收,长期对象升至Gen1/2。触发条件:内存不足、手动调用 GC.Collect()

IDisposable 接口用途
释放非托管资源(如文件句柄)。结合 using 语句确保资源释放:

using (var stream = new FileStream("file.txt", FileMode.Open)) {
    // 使用资源
}

弱引用(WeakReference
允许对象被GC回收,适用于缓存场景。通过 Target 属性访问对象,若为 null 表示已回收。


LINQ 与集合

LINQ 查询语法与方法语法
查询语法类似SQL;方法语法使用Lambda表达式。两者可混合使用,编译后均为方法调用。
示例代码:

var results = from p in products 
              where p.Price > 100 
              select p.Name;
// 等效于
var results = products.Where(p => p.Price > 100).Select(p => p.Name);

IEnumerableIQueryable 区别
IEnumerable 在内存中操作;IQueryable 将查询转换为表达式树(如SQL),由提供者(如Entity Framework)解析。


高级特性与框架

反射的应用场景
动态加载程序集、获取类型信息、调用方法或属性。示例:

Type type = typeof(MyClass);
object instance = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod("MethodName");
method.Invoke(instance, null);

依赖注入(DI)实现方式
通过构造函数、属性或方法注入依赖。常用框架:Microsoft.Extensions.DependencyInjection。
示例:

services.AddTransient<IService, MyService>();

yield return 的作用
实现迭代器模式,延迟生成序列。每次调用返回一个元素,保留当前执行状态。
示例:

IEnumerable<int> GetNumbers() {
    for (int i = 0; i < 10; i++) {
        yield return i;
    }
}

更多推荐