C# 与.NET 基础

一、值类型与引用类型的区别

从内存分配、堆栈存储、复制方式等方面说明。
列举常见的值类型和引用类型。

1 内存分配与存储

值类型:

直接存储数据本身。

通常分配在 栈 上(但当作为类的成员时,随对象存储在堆中)。

变量赋值时复制完整数据(深拷贝)。

引用类型:

存储数据的内存地址引用。

实例分配在 堆 上,变量保存堆内存地址(栈中存储引用)。

变量赋值时复制引用地址(浅拷贝)。

2 常见类型

值类型:

基本数值类型(int, double, bool)

结构体(struct,如 DateTime)

枚举(enum)

引用类型:

类(class,如 string、object)

数组(int[])

接口(interface)

委托(Delegate)

3 示例对比

int a = 10;       // 值类型(栈中存储 10)
int b = a;        // 复制值(b=10,独立于 a)
object obj = new object();  // 引用类型(堆中分配内存,obj 存储地址)
object obj2 = obj; // 复制引用(obj2 和 obj 指向同一对象)

二、异步编程

async/await的作用是什么?如何避免异步方法中的死锁?
对比Task.Run和Task.Factory.StartNew的使用场景。

1 async/await 的作用

简化异步编程模型:避免回调嵌套,以同步代码风格编写异步逻辑。

非阻塞:await 释放当前线程(如 UI 线程)去处理其他任务,直到异步操作完成。

状态机生成:编译器将 async 方法转换为状态机,管理异步操作的暂停与恢复。

2 避免异步死锁

2.1避免阻塞异步任务:

错误做法:在同步代码中调用 .Result 或 .Wait(),导致线程阻塞。

正确做法:始终使用 await 代替阻塞操作。

2.2配置上下文无关:

在库代码中调用 ConfigureAwait(false),避免捕获原始同步上下文(如 UI 上下文)。


var result = await SomeAsyncMethod().ConfigureAwait(false);

2.3 Task.Run vs Task.Factory.StartNew

(1)Task.Run:

默认使用线程池调度任务。

适用于简单的 CPU 密集型任务。
await Task.Run(() => Calculate(1000));

(2)Task.Factory.StartNew:

提供更多控制选项(如 TaskCreationOptions.LongRunning)。

适用于需要定制任务行为的场景(如长时间运行的任务)。

var task = Task.Factory.StartNew(
    () => ProcessData(),
    TaskCreationOptions.LongRunning
);

三、委托与事件

委托的本质是什么?事件和委托的关系是什么?
举例说明如何在 C# 中自定义事件。

1 委托的本质

类型安全的函数指针:委托是一种类(System.Delegate 的派生类),定义方法签名。

多播能力:一个委托实例可以绑定多个方法(通过 += 添加)。

2 事件与委托的关系

(1) 事件是委托的封装:

事件基于委托类型,但仅允许类内触发(外部只能订阅或取消订阅)。

提供更安全的观察者模式实现。

(2)示例:


public delegate void ClickHandler(object sender, EventArgs e);
public class Button
{
    public event ClickHandler? Clicked;  // 事件声明
    public void OnClick()
    {
        Clicked?.Invoke(this, EventArgs.Empty);  // 触发事件
    }
}

3 自定义事件示例

public class TemperatureMonitor
{
    public delegate void TemperatureChangedHandler(double newTemp);
    public event TemperatureChangedHandler? TemperatureChanged;

    private double _currentTemp;
    public double CurrentTemp
    {
        get => _currentTemp;
        set
        {
            _currentTemp = value;
            TemperatureChanged?.Invoke(value);  // 触发事件
        }
    }
}

四、异步编程特性(Attribute)

关于 “精通ASP.NET MVC”,请说明[HttpGet]、[Route]等特性的作用,以及如何自定义特性。

1 ASP.NET MVC 中的特性作用

(1) [HttpGet]:限制 Action 方法仅响应 HTTP GET 请求。

[HttpGet]
public ActionResult GetUser(int id) { ... }

(2) [Route]:定义 URL 路由模板,映射请求到 Action 方法。

[Route("api/users/{id}")]
public ActionResult GetUserById(int id) { ... }

2 自定义特性步骤

(1)继承 Attribute 类:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class AuditLogAttribute : Attribute
{
    public string LogMessage { get; }
    public AuditLogAttribute(string message) => LogMessage = message;
}

(2)应用特性:

[AuditLog("User data accessed")]
public ActionResult GetUser(int id) { ... }

(3)通过反射读取特性:

var method = typeof(HomeController).GetMethod("GetUser");
var auditAttr = method.GetCustomAttribute<AuditLogAttribute>();
Console.WriteLine(auditAttr?.LogMessage);  // 输出 "User data accessed"
posted @ 2025-05-28 09:37  青云Zeo  阅读(18)  评论(0)    收藏  举报