LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

如何优雅地实现 C# 的 Using 语法糖

freeflydom
2026年8月4日 10:44 本文热度 35

C# 日常开发中,资源管理是一个常见但容易出错的问题。无论是数据库连接、文件句柄还是信号量,忘记释放资源都可能导致内存泄漏、死锁等严重问题。

传统的 try-finally块虽然可靠,但代码冗长且容易遗漏。C# 提供了一个比较优雅的解决方案:使用using语句。但要让自定义资源支持 using,需要按照特定的模式。

无意中在ABP vNext框架中看到了人家的实现,作为笔记记录下来,下面将以 SemaphoreSlim为例,演示一下封装支持 using语法糖的自定义资源管理器。

一、问题的根源

考虑以下常见的信号量使用模式:


private readonly SemaphoreSlim _semaphore = new(1, 1);
private Guid _currentGuid = Guid.NewGuid();
public async Task AccessResourceAsync()
{
    Console.WriteLine($"线程 {_currentGuid} 等待访问资源.");
    bool isGet = await _semaphore.WaitAsync(1000);
    if (!isGet)
    {
        Console.WriteLine($"线程 {_currentGuid} 指定时间内未获取资源,丢弃.");
        return;
    }
    try
    {
        Console.WriteLine($"线程 {_currentGuid} 已经进入获取资源.");
        // 执行关键业务逻辑
        await DoCriticalWorkAsync();
    }
    finally
    {
        Console.WriteLine($"线程 {_currentGuid} 已经释放资源.");
        _semaphore.Release();
    }
}

这段代码存在几个问题:

1.模板代码过多:每次使用信号量都要写相同的获取/释放逻辑

2.容易出错:忘记写 finally块会导致死锁

3.可读性差:业务逻辑被资源管理代码淹没

二、理解 Using 的本质

C# 的 using语句本质上是一个语法糖,编译器会将其转换为标准的 try-finally 块:

// 你写的代码:
using (var resource = GetResource())
{
    // 使用资源
}
// 编译器生成的代码:
var resource = GetResource();
try
{
    // 使用资源
}
finally
{
    if (resource != null)
        ((IDisposable)resource).Dispose();
}

关键点:

能被using包裹的必须是实现了 IDisposable接口的对象,且 Dispose()方法会在finally块中被调用

三、实现自定义 Using 支持
首先,我们需要使用委托来创建一个通用的包装器,将任意释放逻辑包装成 IDisposable:

public class DisposeAction : IDisposable
{
    private readonly Action _action;
    public DisposeAction(Action action)
    {
        _action = action;
    }
    public void Dispose()
    {
        _action?.Invoke();
    }
}

1.使用SemaphoreSlim封装

public static class SemaphoreSlimExtension
{
    public static async Task<IDisposable> LoctkAsync(this SemaphoreSlim semaphoreSlim, int duration, Guid guid)
    {
        Console.WriteLine($"线程 {guid} 等待访问资源.");
        bool isGet = await semaphoreSlim.WaitAsync(1000);
        if (!isGet)
        {
            Console.WriteLine($"线程 {guid} 指定时间内未获取资源,丢弃.");
            return default(IDisposable);
        }
        Console.WriteLine($"线程 {guid} 已经进入获取资源.");
        return GetDispose(semaphoreSlim, guid);
    }
    private static IDisposable GetDispose(this SemaphoreSlim semaphoreSlim, Guid guid)
    {
        return new DisposeAction(() =>
        {
            DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new(9, 1);
            defaultInterpolatedStringHandler.AppendLiteral("线程");
            defaultInterpolatedStringHandler.AppendFormatted<Guid>(guid);
            defaultInterpolatedStringHandler.AppendLiteral("已经释放资源.");
            Console.WriteLine(defaultInterpolatedStringHandler.ToStringAndClear());
            //Console.WriteLine($"线程{guid}已经释放资源.");
            semaphoreSlim.Release();
        });
    }
}

四、实际使用示例

private readonly SemaphoreSlim _semaphore = new(1, 1);
public async Task ProcessDataAsync()
{
    // 优雅的 using 语法
    using (await _semaphore.LockAsync(5000, "数据处理"))
    {
        // 临界区代码
        Console.WriteLine("开始处理关键数据...");
        await Task.Delay(1000);
        Console.WriteLine("数据处理完成");
    } // 这里会自动释放信号量
}

通过将自定义资源包装成 IDisposable,可以充分利用 C# 的 using语法糖,撸出安全优雅的代码。这种模式适用于信号量,当然还可以扩展到数据库连接、文件锁、事务管理等任何需要确定释放的资源。

阅读原文:点击这里


该文章在 2026/8/4 10:44:26 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-9  粤公网安备44030602007207号